Specifying dependencies on Haskell code

Roman Leshchinskiy rl at cse.unsw.edu.au
Mon May 12 09:53:55 EDT 2008


Simon Marlow wrote:
> 
> We already have interfaces, in the sense that a package *is* an 
> interface.  You're suggestion decoupling these notions, which I believe 
> would add a lot of extra complexity without enough benefit to make it 
> worthwhile.

Well, a package is an interface in the sense that it incidentially 
defines one. However, I have no idea how to extract the interface from 
the package. I also don't really understand how to depend on it (see below).

In general, I think it's fair to say that what we have now is somewhat 
akin to dynamic typing of packages. I'd like to have static typing. I 
expect the benefits to be similar to those of static over dynamic 
typing. As to the complexity, I don't think having explicit interfaces 
would be much more complex than implementing a tool which checks that 
the package versioning policy is being followed.

> Let's take the examples you gave above:
> 
> 1. several packages could implement the same interface.  This can be 
> done by having a single package that exports an interface and depends on 
> one of the underlying "providers" selected at build-time.

By build-time, do you mean when building the application which depends 
on the interface or when building the interface package? I'm interested 
in the former but I suspect you mean the latter.

As an example, suppose Alice writes a package and Bob writes an 
application that depends on it. Now, Chris doesn't like Alice and forks 
her package. He now wants to build Bob's application with his package 
instead of Alice's. How can he do it at the moment without having Alice 
and/or Bob apply any patches to their stuff? What if instead of an app, 
Bob writes a package which other apps depend on?

> 2. fine-grained dependencies: just split up packages, or define new 
> packages that just re-export parts of existing packages, if that's what 
> you want.

I don't think that splitting up packages is really an option since the 
packages' authors wouldn't always agree to it and in any case, we don't 
want to have a lot of artificially small packages. Reexporting would 
work, I guess, but do I now have to distribute all those packages which 
just reexport along with my stuff? I general, IMO packages and 
interfaces are simply at different levels of granularity.

To make this more concrete: suppose Alice implements package trees and 
Bob package containers. Both contain compatible implementations of AVL 
trees. Chris need AVL trees in his application but doesn't care where 
they come from and wants his users to be able to pick one when building 
the app. What does he do? And how do Alice and Bob ensure that their 
implementations are, in fact, compatible?

> 3. one package could implement several versions of an interface.  This 
> is no different from having several versions of a package that can all 
> be installed and used together.

I have to disagree here. There is quite a difference between maintaining 
a legacy interface in new versions of software and maintaining several 
versions of that software. Suppose I write a package and a lot of 
applications (not necessarily mine) depend on version 1 of that package. 
Now, for version 2 I completely redesign it such that the interface 
becomes incompatible with version 1. Unless there is a way for me to 
somehow provide the version 1 interface in my version 2 package, I'll 
have to keep maintaining the old version until all those applications 
migrate.

This can be done now, I suppose, but not without jumping through some hoops.

> 4. interface definitions could have QuickCheck properties.  Absolutely! 
> And packages can have QuickCheck properties too.

Of course, but these properties can't be easily shared between packages 
which implement the same interface. Suppose Alice implements a package 
and Bob wants to reimplement it. He can copy Alice's QuickCheck 
properties into his code, of course, but that means that he we now have 
two sets of those properties which will be maintained separately.

Also, these properties aren't really visible to a package's client at 
the moment since we don't even have a convention where to put those. 
IIUC, they aren't even considered part of the interface when it comes to 
package versioning. This is bad!

> Using the Package Versioning Policy we have a clear way to know when a 
> package's interface has changed, or when the interface has remained the 
> same but the implementation has changed.  We need tool support to check 
> that the author is adhering to the PVP, though.

What will this tool check? That the set of exported names doesn't 
change? That they have the same signatures? That the QuickCheck 
properties remain the same? That the package satisfies the same theories 
(once we have support for formal reasoning)? If the answer to any of the 
above is no, then why not? On the other hand, if  it will do all of the 
above, then wouldn't it be much easier to explicitly specify the 
interface instead of having to extract it from the package somehow?

Also, I don't really understand how PVP is supposed to work, to be 
honest. If all I need is function doThis from package foo 1.0, what do I 
depend on? foo 1.*? What if foo 2.0 has a slightly different interface 
but still exports doThis?

Finally, I was always under the impression that PVP is something we want 
to have for the core packages. I didn't realise that it is supposed to 
be a universally accepted policy and I don't think that would work. 
Almost all software companies, for instance, have their own versioning 
policy. We can't make them use ours. In general, the larger the Haskell 
community becomes the less likely it will be that any kind of convention 
will work. We ought to plan for the future and adopt an approach that 
scales.

> Basically the current scheme minimizes the cognitive load by having a 
> single concept (the package) that embodies several units: distribution, 
> licensing, dependency, linking (amongst others).

I have my doubts about minimizing the cognitive load. To return to the 
dynamic vs. static typing analogy: although static typing requires more 
bookkeeping and introduces more concepts, it certainly leads to less 
cognitive load for me. Abstraction barriers are good! Well, as long as 
there aren't too many but at the moment, we don't have *any*.

Roman



More information about the Libraries mailing list