[Haskell-cafe] Re: Unexported functions are evil

2005-05-17 Thread Peter Simons
Thanks for your opinions everybody!


Ketil Malde writes:

  I guess you could sometimes have name clashes as well?

I was afraid about those for the longest time too, but in
practice name clashes curiously enough hardly ever occur --
in my experience. The problem only arises when you actually
_use_ a function that's ambiguous, just importing two
modules with a function called 'foo' in them is no problem.
And then you still have the option of using 'hide' or
'qualified' when importing the modules.


  On those occasions, however, why not put the function
  into a module, say Foo.Bar.Private and import it into
  Foo.Bar from there?

  So you don't want to automatically re-export imports, I
  take it? :-)

No. ;-) Although I would like to have a shortcut for saying
(re-)export everything.


David Roundy writes:

  [...] why not put the function into a module, say
  Foo.Bar.Private and import it into Foo.Bar from
  there?

  Because a separate module is more work.

It sure is, but I don't think that it's more work or it's
less work is a good principle by which to make software
design decisions. If you follow this idea through, then you
could also argue that splitting a program into separate
functions is more work than writing one big, big 'main'
function for the task. And it sure is. Still enlightened
programmers do just that, because it often turns out that
doing so is _less work_ in the long run. I believe the same
applies to cleanly grouping functions into separate modules,
and a separation between public API and internal
implementation doesn't sound so unreasonable, IMHO.


  Almost every module I write has private functions, and
  I'd really not want to write twice as many modules.

Why do these functions need to be private?


  In darcs, if someone needs to play with fire, he can do
  it right there in the module itself, and export a new
  interface function.

Not really, unless you decide to include the patches into
the main distribution. If you don't, someone who wants to
access the internals essentially has to create a fork of
your software, and that's something you really want to avoid
if you want to encourage re-use.


  In the case of darcs, I'd say that the whole point of
  using modules (besides making things faster to compile)
  is to place these barriers, so that one can modify an
  individual module without worrying about the rest of the
  code, as long as one keeps the interface fixed.

I'm not sure whether I understand that. When modifying a
function 'foo', why do you have to worry _less_ about 'bar'
if it is in a separate module than you'd have to if it would
be in the same module?


  There's also the ease of bug-writing issue. I think that
  exported interfaces should be the sorts of functions
  where the meaning of the function can be guessed from its
  name and type.

Shouldn't _any_ function have those properties if at all
possible?


ajb writes:

  Is there any reason why you would have a function in one
  of your modules and _not_ export it?

  Because that function is nobody else's business.

I'm sorry, but that's not really a convincing technical
argument, that's essentially because I want it so.


  So while I think you've identified a real problem (the
  modules that you want to use expose insufficient APIs), I
  think your solution is wrong. The right solution is to
  complain to the module writer, and ask them to export a
  functionally complete API.

So my solution is wrong and your solution is right. ;-)
Having that out of the way, what are your reasons for this
opinion? (Other than that the art of programming says it
ought to be this way.)


  The only reason I could think of is that a function is
  considered to be internal [...]

  Right. And I agree with David: This is reason enough.

How is an internal function any _more_ internal if you don't
export it? How is it less internal if you _do_ export it?
Why doesn't the approach

  -- | /Attention:/ this function is internal and may change
  --  at random without even so much as shrug.

  foo = ...

suffice?


  With my business hat on: Every time you expose something
  for use, you must at the very least document it.

I'd recommend documenting _all_ functions I write, not just
the exported ones.


  Taking this to an illogcial extreme, why don't we allow
  pointer arithmetic in Haskell, but require people to
  import Prelude.C first, so that people who enjoy
  playing with fire can do it?

You mean Foreign.Ptr? Curiously enough, if Haskell
wouldn't support pointer arithmetic, the language would be
completely useless to me, so I for one don't think that's
taking things to the illogical extreme.


Iavor Diatchki writes:

  [...] in practice this is likely to often lead to
  recursive modules [...]

Why is that? My intuition would say that the exact opposite
is true: a more fine-grained set of modules is _less_ likely
to require recursive modules. But that's just intuition. Do
you have an concrete example which illustrates 

Re: [Haskell-cafe] Re: Unexported functions are evil

2005-05-17 Thread Iavor Diatchki
Hello,

On 17 May 2005 12:09:35 +0200, Peter Simons [EMAIL PROTECTED] wrote:
 Iavor Diatchki writes:
 
   [...] in practice this is likely to often lead to
   recursive modules [...]
 
 Why is that? My intuition would say that the exact opposite
 is true: a more fine-grained set of modules is _less_ likely
 to require recursive modules. But that's just intuition. Do
 you have an concrete example which illustrates this point?

The smaller the modules are the more likely it is that they will end
up being recursive.  To see that, consider the extreme where every
function is in a separate module, then all recursive groups of
functions will end up being recursive groups of modules.   As a more
practical example consider a file A.hs that defines some data type T
and exports a function f that is defined in terms of a private
function g.  Now if we place g in a file called Private.hs then
A needs to import Private, but also Private needs to import A for
the definition of T.

-iavor
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Re: Unexported functions are evil

2005-05-17 Thread Peter Simons
Iavor Diatchki writes:

  Do you have an concrete example which illustrates this
  point?

  [...] consider a file A.hs that defines some data type T
  and exports a function f that is defined in terms of a
  private function g. Now if we place g in a file
  called Private.hs then A needs to import Private, but
  also Private needs to import A for the definition of
  T.

Ah, now it see it! Great example.

But couldn't you just put T in Foo/Base.hs, g in
Foo/Private.hs, then create Foo/API.hs which imports
Foo/Base.hs and Foo/Private.hs, and leave f in A.hs
and import Foo/API.hs?

Peter

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe