Re: Packages and modules

John Meacham
Package names should never appear in source files IMHO. if a package name is in the source file, then you might as well make it part of the module name. Packages exist for 'meta-organization' of code. A way to deal with mapping code _outside_ of the language itself, putting packages inside the code will force the creation of yet another level, meta-packages, or something. packages should not be a language issue, they are an environment one.
I tend to the opposite view. The meaning of the code should be expressed in the code itself. If a module M imports A.B.C, and I can see two such modules called A.B.C, then the meaning of the code is ambiguous and ill-defined. I would rather not have to look elsewhere (in the build system? Makefile? scons? Cabal file? DOS batch file? where?) to find out how to resolve the ambiguity. Surely the programmer knew which import was intended. Is it so difficult to communicate that information somewhere close to the import itself? This is the same situation as with compiler flags for language extensions, foreign imports, and so on. If a module uses a non-standard language feature that changes the interpretation of the syntax (e.g. template haskell), it should say so in the module itself {-# OPTIONS_GHC -fth #-}, so that I as a human reader know what is going on. Likewise, if a foreign import requires a C header file, that should also be referred to in the FFI decl, not solely as a build option at some arbitrary distance in the filesystem. Regards, Malcolm

Malcolm Wallace
John Meacham
wrote:
I tend to the opposite view. The meaning of the code should be expressed in the code itself.
Sounds like a reasonable principle.
If a module M imports A.B.C, and I can see two such modules called A.B.C, then the meaning of the code is ambiguous and ill-defined.
Surely this depends on the relationship between the two A.B.C., and I think you make the underlying assumption that they implement different things. But I think it's far from uncommon that they are intended to implement the same funcitonality. E.g I might be developing my A.B.C to be used as a replacement for somebody else's A.B.C. Or perhaps I just want to check out performance with the latest development version of A.B.C. Now, to be able to test my version without rewriting all client code, I suppose I must download and modify the entire package containing somebody else's A.B.C, and replace A.B.C with my version in it. I'd much rather do this substitution from the command line; ghc -hide foo -package myfoo ... Another case that nobody seem to have mentioned, is what happens if I move a module from one package to another. Say somebody finds out that 'base' is getting crowded, and wants to move Data.Set to 'collections'. Annotated imports would then have to be updated, while ghc --make would quickly work out the unannotated imports, and do the right thing. -k PS: Talking about module A.B.C seems a bit abstract. Perhaps the wiki page could be updated with some examples of namespace collisions that people have experienced? -- If I haven't seen further, it is by standing in the footprints of giants

Ketil Malde
If a module M imports A.B.C, and I can see two such modules called A.B.C, then the meaning of the code is ambiguous and ill-defined.
Surely this depends on the relationship between the two A.B.C., and I think you make the underlying assumption that they implement different things.
No, I agree that they may be essentially the same module, but one of them has a bugfix, or a new API call, or something.
Now, to be able to test my version without rewriting all client code, I'd much rather do this substitution from the command line; ghc -hide foo -package myfoo ...
With the Simons' proposal, and with Brian's, you would need to edit the source code at all usage positions of "import A.B.C". I agree that this is tedious and undesirable. With my proposal, you could organise your source code such that only a single file might need to be edited, replacing say module Foo (namespace F) where import namespace "foo" as F with module Foo (namespace F) where import namespace "myfoo" as F
Another case that nobody seem to have mentioned, is what happens if I move a module from one package to another. Say somebody finds out that 'base' is getting crowded, and wants to move Data.Set to 'collections'. Annotated imports would then have to be updated,
Again, I believe my proposal would permit a single update, whilst the other proposals would require multiple updates. http://hackage.haskell.org/trac/ghc/wiki/GhcPackagesWithGrafting
PS: Talking about module A.B.C seems a bit abstract. Perhaps the wiki page could be updated with some examples of namespace collisions that people have experienced?
One thing I would very much like to be able to write is regression testing over libraries. Does the computation P using package HaXml-1.15 give the same result as running P with package HaXml-1.13? At the moment, one cannot write such a test directly in Haskell, one must escape to a separate test harness. Regards, Malcolm

Malcolm Wallace
No, I agree that they may be essentially the same module, but one of them has a bugfix, or a new API call, or something.
This brings up an interesting point: if I need a bugfix from version X, later packages will probably also be okay. So it should be possible to do: import A.B.C from "foo >= X" How about minor/major revisions?
Now, to be able to test my version without rewriting all client code, I'd much rather do this substitution from the command line; ghc -hide foo -package myfoo ...
With the Simons' proposal, and with Brian's, you would need to edit the source code at all usage positions of "import A.B.C".
I thought Simons' (and perhaps also Brian's) still allowed package juggling from the command line - is that incorrect? I.e. is "import from.." intended to be the *only* way of specifying packages? Cabal lets you specify package dependencies, at least for the program as a whole - doesn't that mean it would have to rewrite the source before compilation? And another issue: presumably the source code is prioritized, so if the cabal file (or command line) specifies -package foo > v2, but the sources specify "foo-2.0", the compilation will fail if only foo-2.1 is installed? Anyway, *if* packages can be juggled at the command line, it should suffice to say: EXTRAFLAGS='-package foo-2.1' make test
is tedious and undesirable. With my proposal, you could organise your source code such that only a single file might need to be edited, replacing say module Foo (namespace F) where import namespace "foo" as F with module Foo (namespace F) where import namespace "myfoo" as F
I think you can do this, as long as symbols are annotated with package names. Even if only command line options are available, you can do something like: {-# OPTIONS -package foo #-} -- or replace with myfoo module F where import Foo And of course, if you want to change the package for your entire project (as opposed to a single module), you edit the Makefile, .cabal, or whatever. If you want to mix parts from different versions in the same module, you can use proxy modules. Something like this, perhaps: Foo03.hs: {-# OPTIONS -package foo-0.3 #-} module Foo03 (module Foo) where import Foo (foo) Foo10.hs: {-# OPTIONS -package foo-1.0 #-} module Foo10 (module Foo) where import Foo (bar) Main.hs: import Foo03(foo) import Foo10(bar) -k PS: Is it correct that -- except for the new functionality in symbols being annotated with package as well as module name -- all of this is just a matter of convenience/syntactic sugar? (Which would explain the volume of the discussion :-) -- If I haven't seen further, it is by standing in the footprints of giants

Ketil Malde
This brings up an interesting point: if I need a bugfix from version X, later packages will probably also be okay. So it should be possible to do:
import A.B.C from "foo >= X"
Yes, I agree, some notion of version ranges might be desirable "1.3.2 <= foo <= 1.3.9" That is one good reason to leave the package name as a quoted string, so such questions can be resolved later in the design exercise, and even changed in the future, without impacting the basic syntax.
How about minor/major revisions?
Yes, you might want "foo-2" to indicate that any of "foo-2.0" up to "foo-2.99.9" are acceptable. If every library author sticks to the rule of no API changes in minor versions, then this might even cover the same territory as the version range idea.
With the Simons' proposal, and with Brian's, you would need to edit the source code at all usage positions of "import A.B.C".
I thought Simons' (and perhaps also Brian's) still allowed package juggling from the command line - is that incorrect? I.e. is "import from.." intended to be the *only* way of specifying packages?
Hmm. I am all in favour of removing the ability to name packages on the commandline, making the source code the definitive specification. (But I have the impression that the other proposals do in fact want to allow both ways of naming packages - source and environment.)
And another issue: presumably the source code is prioritized, so if the cabal file (or command line) specifies -package foo > v2, but the sources specify "foo-2.0", the compilation will fail if only foo-2.1 is installed?
Just one example of why it is better to have only one way of naming the package dependencies. The whole question of conflicts between source and command-line is nasty.
Cabal lets you specify package dependencies, at least for the program as a whole - doesn't that mean it would have to rewrite the source before compilation?
If the packages are named in the source, then an automated tool can gather all the dependencies and write the Cabal file for you. The Cabal file is descriptive, not prescriptive. I see it essentially as a cache of information (packages needed, source file names, language extensions) that is otherwise already available directly from the source in a scattered fashion.
With my proposal, you could organise your source code such that only a single file might need to be edited, replacing say module Foo (namespace F) where import namespace "foo" as F with module Foo (namespace F) where import namespace "myfoo" as F
I think you can do this, as long as symbols are annotated with package names. Even if only command line options are available, you can do something like:
{-# OPTIONS -package foo #-} -- or replace with myfoo module F where import Foo
No, I think you missed the point. Let's say there are 30 files that import modules from the package "foo". At the moment, and with the current proposal, when you decide to replace "foo" with "myfoo", you must edit all 30 files to change the OPTIONS line (or the "import from" specs). The key new concept in my proposal, by contrast, is that you can manage the visibility of namespaces separately from the particular usages of the namespace (i.e. module imports). This makes it possible to locate the specification of package "foo" in a single file, and when you change to "myfoo", only the one file needs to be edited.
PS: Is it correct that -- except for the new functionality in symbols being annotated with package as well as module name -- all of this is just a matter of convenience/syntactic sugar? (Which would explain the volume of the discussion :-)
For the current proposal, yes. For my extended proposal, no, it introduces a new language concept that was not previously expressible. Regards, Malcolm

Malcolm Wallace
{-# OPTIONS -package foo #-} -- or replace with myfoo module F where import Foo
No, I think you missed the point. Let's say there are 30 files that import modules from the package "foo". At the moment, and with the current proposal, when you decide to replace "foo" with "myfoo", you must edit all 30 files to change the OPTIONS line (or the "import from" specs).
This is a red herring, you could use a proxy module with either option (and in the example you quote, I meant to re-export Foo of course. Sorry.) Or, you could use a global command line instead of local pragmas/import modifiers. As I understand your proposal at http://cvs.haskell.org/trac/ghc/wiki/GhcPackageNamespaces , the main contribution from namespaces is to introduce an intermediate level between packages and modules. (Which of course is useful when the packages encompass a lot of functionality.) -k -- If I haven't seen further, it is by standing in the footprints of giants

Malcolm Wallace
PS: Is it correct that -- except for the new functionality in symbols being annotated with package as well as module name -- all of this is just a matter of convenience/syntactic sugar? (Which would explain the volume of the discussion :-)
For the current proposal, yes.
Then I'm not convinced it is worth introducing new import syntax. I think 90% of the cases of ambiguity should be resolved globally for the project, i.e. by compiler switches (typically in .cabal, Makefile, or similar). These cases include using newer versions of standard packages, regression testing for library versions, or alternative implementations. For the remaining (and bear in mind that nobody have put forward anything but hypothetical examples yet), I think a proxy module is sufficient as a solution. This is necessary where one program needs to simultaneously use modules with the same hierarchical name from different packages. And the advantage of making this hurt a bit, is that it puts pressure on different-functionality modules to populate different locations in the hierarchical namespace - the pain here is a feature, not a bug. (Please enlighten me if I'm missing some important cases here.) -k -- If I haven't seen further, it is by standing in the footprints of giants

On 2006-07-06, Malcolm Wallace
John Meacham
wrote: Package names should never appear in source files IMHO. if a package name is in the source file, then you might as well make it part of the module name. Packages exist for 'meta-organization' of code. A way to deal with mapping code _outside_ of the language itself, putting packages inside the code will force the creation of yet another level, meta-packages, or something. packages should not be a language issue, they are an environment one.
I tend to the opposite view. The meaning of the code should be expressed in the code itself. If a module M imports A.B.C, and I can see two such modules called A.B.C, then the meaning of the code is ambiguous and ill-defined. I would rather not have to look elsewhere (in the build system? Makefile? scons? Cabal file? DOS batch file? where?) to find out how to resolve the ambiguity. Surely the programmer knew which import was intended. Is it so difficult to communicate that information somewhere close to the import itself?
Then, as John points out, how is package Foo module A.B.C and package Bar module A.B.C any different than modules Foo.A.B.C and Bar.A.B.C? (And I agree with Ketil about when it is useful to specify this outside the source, unlike your flag example.) -- Aaron Denney -><-

Aaron Denney
Package names should never appear in source files IMHO.
I tend to the opposite view.
Then, as John points out, how is package Foo module A.B.C and package Bar module A.B.C any different than modules Foo.A.B.C and Bar.A.B.C?
I have great sympathy with this view - that packages are little different from a top-level name in the hierarchy. But Simon PJ's comment (on the wiki page) about the difference between specifying the _purpose_ of a module in its name, and the _provenance_ of a module in its package identifier, was very convincing. I have added (yet another) alternative proposal, to the wiki here: http://hackage.haskell.org/trac/ghc/wiki/GhcPackagesWithGrafting The details overlap significantly with the current proposals, but the main contribution I am trying to bring to the table is the (old but never implemented) idea of grafting a sub-hierarchy at an arbitrary location. This idea has a close relationship with specifying what package a module should come from. So, I have tried to combine the two. Regards, Malcolm

Malcolm Wallace wrote:
Aaron Denney
wrote: Package names should never appear in source files IMHO.
I tend to the opposite view.
Then, as John points out, how is package Foo module A.B.C and package Bar module A.B.C any different than modules Foo.A.B.C and Bar.A.B.C?
I have great sympathy with this view - that packages are little different from a top-level name in the hierarchy.
But Simon PJ's comment (on the wiki page) about the difference between specifying the _purpose_ of a module in its name, and the _provenance_ of a module in its package identifier, was very convincing.
I have added (yet another) alternative proposal, to the wiki here: http://hackage.haskell.org/trac/ghc/wiki/GhcPackagesWithGrafting
I've digested this, and I hope can regurgitate the key points for anyone wishing to grasp it quickly. Please correct me if I get anything wrong: - the proposal is to let you specify grafting in the source code - you graft a *sub-hierarchy* of a package anywhere in the global module namespace (the sub-hiearchy bit is new, I haven't seen this proposed before). - you can also graft a sub-hierarchy of a package onto the *current module*, so that it becomes available when importing this module. This is new too. Personally I'm not convinced the extra generality of grafting sub-hierarchies is necessary. The re-export idea is interesting, though. Cheers, Simon

Simon Marlow
http://hackage.haskell.org/trac/ghc/wiki/GhcPackagesWithGrafting
Please correct me if I get anything wrong:
- the proposal is to let you specify grafting in the source code
This is not the main focus of the proposal. Grafting is one oft-requested feature that is not currently supported, but yet it seems very close to the idea of specifying a package dependency in the source code. So my intention is merely to take it into account when designing the latter facility. If one mechanism (with a little tweaking) can achieve both aims, so much the better. The central plank of my proposal is to introduce an explicit concept of "namespace". Namespaces can be managed separately from the imports that range over them. That's it.
- you graft a *sub-hierarchy* of a package anywhere in the global module namespace (the sub-hiearchy bit is new, I haven't seen this proposed before).
The ability to graft hierarchies is just a side-effect. I would phrase this point as - a "namespace" is a sub-hierarchy of the modules contained in a package. (The sub-hierarchy bit is indeed new.)
- you can also graft a sub-hierarchy of a package onto the *current module*, so that it becomes available when importing this module. This is new too.
Again, I would rephrase this: - "namespaces" can be imported and exported, separately from the modules they contain. (Yes, this is new too.) Regards, Malcolm

So I don't like this idea of re-exporting namespaces. Here's why. When I see 'import M', I have to search not only the filesystem, but also for possible namespaces re-exported by *all* the other import declarations in the file, which means I have to understand all those other import declarations, and the process is recursive. eg. in the example from the wiki: module Gtk (namespace AllOfGtk) where import namespace "gtk-2.4" Graphics.UI.Gtk as AllOfGtk module MyGUI where import Gtk import Button ..... Button.label ..... In this example, Button is in the namespace re-exported by Gtk, but the reverse might just as well be true, we have no idea when compiling MyGUI. If this is hard for the compiler, it's hard for the user too. Someone understanding your source code has a lot of places to look to find the target of an import. ----------- I believe there should be a clean separation between - constructing the global module namespace, and - interpreting the source code of a module that is, mapping an import declaration to a module should require nothing more than searching the filesystem and package database. This is true now, and I think we should ensure it remains true, for the benefit of tool and language implementors. Of course the import declarations are free to change the module namespace as it is presented to the source code: modules can be renamed, or maybe even grafted, but these declarations scope only over the source code of the module, and have no effect on other import declarations. Incedentally, this same problem crops up with qualified exports, and it is one reason I don't like qualified exports either. Cheers, Simon

Simon Marlow
So I don't like this idea of re-exporting namespaces. Here's why.
When I see 'import M', I have to search not only the filesystem, but also for possible namespaces re-exported by *all* the other import declarations in the file, which means I have to understand all those other import declarations, and the process is recursive.
True. But I don't see how it is much different from ordinary imports: if an entity e is used in the source text, but not defined there, you must search the modules that are imported to see where e was defined. In general, e might not be explicitly defined in /any/ of the directly-imported modules, so you must recursively check their imports/re-exports.
If this is hard for the compiler, it's hard for the user too. Someone understanding your source code has a lot of places to look to find the target of an import.
I think it is rather easy for the compiler actually. Agreed that it provides a slight extra burden on the human reader. But I don't think it is significantly larger than the current burden of knowing the definition site of a function.
I believe there should be a clean separation between - constructing the global module namespace, and - interpreting the source code of a module
OK, but that is in direct conflict with the original proposal (to specify a package alongside a module import), which abandons the idea of a "global" module namespace! Indeed, the whole motivation was that we _don't_ want a global module namespace, because that would require all modules in all packages to have unique names.
that is, mapping an import declaration to a module should require nothing more than searching the filesystem and package database. This is true now, and I think we should ensure it remains true, for the benefit of tool and language implementors.
At the moment, the compiler must search the filesystem, package database, and *interface files* (for imports/re-exports). With explicit namespaces, nothing changes there (except that namespaces must also be recorded in the interface files). Regards, Malcolm

Malcolm Wallace wrote:
Simon Marlow
wrote: So I don't like this idea of re-exporting namespaces. Here's why.
When I see 'import M', I have to search not only the filesystem, but also for possible namespaces re-exported by *all* the other import declarations in the file, which means I have to understand all those other import declarations, and the process is recursive.
True. But I don't see how it is much different from ordinary imports: if an entity e is used in the source text, but not defined there, you must search the modules that are imported to see where e was defined.
The big difference is that under your proposal it affects finding the modules in the first place, not just resolving identifiers in the source code. So hmake is affected, likewise the dependency phase of ghc --make. Consider that at the moment, an import declaration can be considered completely independently of the rest of the module. Imports do not affect each other. This is true now (note that 'as' doesn't affect other imports), and in the other packages proposals. Under your proposal, all imports have to be considered together to determine whether any are ambiguous. We can't do Hugs-style one-at-a-time import chasing, for example. It's also inconsistent with the current behaviour of 'as'. In hmake you have the option of trying to do a complete job, which is hard, or just ignoring imports that you can't resolve on the grounds that they might be namespace re-exports. The latter defers some errors until compile time.
I believe there should be a clean separation between - constructing the global module namespace, and - interpreting the source code of a module
OK, but that is in direct conflict with the original proposal (to specify a package alongside a module import), which abandons the idea of a "global" module namespace!
No - there's still a global module namespace, but it is indexed by (package name, module name) pairs. Perhaps I shouldn't have used the word "global". Imagine I'd left it out. Constructing the module namespace is something that can be done by a simple dependency analysis if the modules in a program - this is done right now by ghc --make and hmake. It only requires parsing source modules to extract the module name and the imported modules, nothing more.
that is, mapping an import declaration to a module should require nothing more than searching the filesystem and package database. This is true now, and I think we should ensure it remains true, for the benefit of tool and language implementors.
At the moment, the compiler must search the filesystem, package database, and *interface files* (for imports/re-exports).
No - note that I said "mapping an import declaration to a module". Not an entity, just a module (to be concrete: which M.hs or M.hi does 'import M' refer to?). This is simple right now; with your proposal it gets a lot harder. I accept that the GhcPackages proposal has a serious shortcoming that your proposal addresses, namely that there's no way to name a package in just one place if you're using package-qualified imports. I don't yet know of a good way to fix this, but I'm fairly sure that generalising the module system with namespaces is not a good power/weight tradeoff. Packages are supposed to be simple things, I can't imagine explaining, let alone completely specifying this system. I've started working on GHC's package system, and the main technological difference - changing the identity of a module to be a (package,module) pair - is quite straightforward. From here, it'll be trivial to allow an import declaration to specify a package. Grafting via command-line options would be a bit more complexity, but not much: the compiler already builds a module name to (package,module) mapping from the package database, and grafting just adds more entries to this mapping. Note that this is done before reading any source code. Things get a bit more tricky if grafting declarations can be in the source code, or {-# OPTIONS #-} pragmas: the modue mapping has to be built for each module, before reading import declarations (that means the dependency analyser has to do it, too). But, if import declarations themselves could augment the module namespace, and we have to store this information in .hi files... that's a whole lot more complexity. I think it's a step too far. Cheers, Simon

Simon Marlow
Consider that at the moment, an import declaration can be considered completely independently of the rest of the module. Imports do not affect each other. Under your proposal, all imports have to be considered together to determine whether any are ambiguous. We can't do Hugs-style one-at-a-time import chasing, for example.
Ah, now I see what you are getting at. Program P imports modules M and N. How do the compiler know where M is located? It must presume the default namespace. But then later, module N might re-export a different namespace which means that M is now ambiguous. Conversely, let's say M is not available in the default namespace. So we must wait until module N has been imported, to see if it brings a namespace into scope that does contain a module M. Very nasty.
I accept that the GhcPackages proposal has a serious shortcoming that your proposal addresses, namely that there's no way to name a package in just one place if you're using package-qualified imports. I don't yet know of a good way to fix this, but I'm fairly sure that generalising the module system with namespaces is not a good power/weight tradeoff.
OK, I accept that my proposal for first-class namespaces is rather too heavy a solution. (But I still think the problem is a real one, and we should keep thinking about other ways to solve it.) Regards, Malcolm

Malcolm Wallace wrote:
I tend to the opposite view. The meaning of the code should be expressed in the code itself. If a module M imports A.B.C, and I can see two such modules called A.B.C, then the meaning of the code is ambiguous and ill-defined. I would rather not have to look elsewhere (in the build system? Makefile? scons? Cabal file? DOS batch file? where?) to find out how to resolve the ambiguity. Surely the programmer knew which import was intended. Is it so difficult to communicate that information somewhere close to the import itself?
I think this is an oversimplification. Usually you want your source code to be abstract with respect to certain properties of the environment: eg. I don't care to include the path to the file containing module M in the source code, so that I can move M around if I need to. Similarly I don't want to specify the exact version of any module I depend on, since the same code probably works with a range of versions. I certainly want to specify that dependency somewhere (but only in one place, eg. foo.cabal). Cheers, Simon

Simon Marlow
Surely the programmer knew which import was intended. Is it so difficult to communicate that information somewhere close to the import itself?
I think this is an oversimplification. Usually you want your source code to be abstract with respect to certain properties of the environment: eg. I don't care to include the path to the file containing module M in the source code, so that I can move M around if I need to. Similarly I don't want to specify the exact version of any module I depend on, since the same code probably works with a range of versions.
I agree with all that. The mapping of the package name to its location in the filespace should not be in the source code. That is the job of a package management tool.
I certainly want to specify that dependency somewhere (but only in one place, eg. foo.cabal).
The question for me is whether the .cabal file therefore counts as source code. Certainly the .cabal file no more specifies where packages are located in the filesystem than do any of the proposals on the table. But if the .cabal file is needed in order to disambiguate the code, what happens if someone wants to use a Makefile instead of Cabal? You can see where this leads - any number of build systems could potentially have an influence on the meaning of the code. So I think one good thing about the current proposals is that they move the package dependencies into the source code itself, where they cannot get lost or forgotten or overlooked. The *dependency* is noted, but the details of how to locate a package are rightly left to tools. But the biggest problem is really your phrase "(but only in one place)". I agree that specifying the dependencies close together is good in principle. But occasionally, you need to have different package dependencies for different modules of a single project - this is a finer granularity of dependency than Cabal is currently good at expressing. Regards, Malcolm

Malcolm Wallace wrote:
But the biggest problem is really your phrase "(but only in one place)". I agree that specifying the dependencies close together is good in principle. But occasionally, you need to have different package dependencies for different modules of a single project - this is a finer granularity of dependency than Cabal is currently good at expressing.
By all means have package names scattered through the source code, but the dependencies still need to be specified in a single place for each project. The main reason is so that tools can grab the dependencies of a package without too much fuss: tools that turn Haskell packages into OS packages, for example. Cheers, Simon

Simon Marlow
this is a finer granularity of dependency than Cabal is currently good at expressing.
By all means have package names scattered through the source code, but the dependencies still need to be specified in a single place for each project. The main reason is so that tools can grab the dependencies of a package without too much fuss: tools that turn Haskell packages into OS packages, for example.
Indeed. No problem with that. Any individual module might have a small and specific set of package dependencies. The project as a whole will have the union of all of those. Regards, Malcolm
participants (4)
-
Aaron Denney
-
Ketil Malde
-
Malcolm Wallace
-
Simon Marlow