RE: Cabal vs Haskell (was RE: build-depends harmful (was RE: import resolution))

On 20 April 2005 11:56, S. Alexander Jacobson wrote:
Lastly, I think you proposal to add package naes to the source is seriously at odds with your commment from earlier:
I'm not proposing to add package names to source code. The rest of your post was based on this misconception, so I won't answer it. I realise my description of the idea wasn't as complete as it could have been. I'll try to describe the idea more precisely. (note this isn't a proposal as such). - source code continues to use module *names* only. - define module *identifier* as (package name, module name) pair - in the context of each module's source, there is assumed to be a mapping from module name to module identifier established by some external mechanism. The "external mechanism" referred to here could be GHC's -package flags, or Cabal's build-depends, for example. For the purposes of the language definition, it doesn't matter.
Also, the Haskell module hierarchy is supposed to reflect functionality, whereas package names are purely administrative. This is a reason for not including package names in source code.
http://www.haskell.org//pipermail/libraries/2005-April/003513.html
My position on this has (still) not changed! Cheers, Simon

Simon, Right now, a module name in an import declaration identifies a module specification, a module name in a module declaration identifies an implementation, and some "external mechanism" resolves specifications to implementations. The big issue on the table here is what exactly this "external mechanism" should be. I'll suggest some requirements: 1. It should require minimal work for a user to share an implementation. 2. It should work with and accross the Internet. 3. It should allow arbitrtary sets of implementations to be delivered together as needed. 4. It should be able to work without substantial user intervention. 5. Module users rather than module authors should select how imported module names are resolved to implementations. 6. Interface changes should be local to users of those interfaces. 7. It needs to handle foreign implementations (FFI) Unfortunately, our existing module resolver mechanisms are severely inadequate here. Build-depends and -package both violate #1 because they both force users to create packages even to share standalone pure haskell modules. The fact that module/package names can't currently be resolved to URLs means both also violate #2 and #4. That packages can contain at most one implementation of any module violates #3 and #5 (and it is just a file format problem!). That package build/install processes can modify overall system state violates #4. Build-depends MAJORLY violates #5 and #6. On the plus side, they both handle #7. I'd like Haskell to have a module resolver mechanism that fulfills our requirements and does not have these problems. -Alex- ______________________________________________________________ S. Alexander Jacobson tel:917-770-6565 http://alexjacobson.com On Wed, 20 Apr 2005, Simon Marlow wrote:
On 20 April 2005 11:56, S. Alexander Jacobson wrote:
Lastly, I think you proposal to add package naes to the source is seriously at odds with your commment from earlier:
I'm not proposing to add package names to source code.
The rest of your post was based on this misconception, so I won't answer it.
I realise my description of the idea wasn't as complete as it could have been. I'll try to describe the idea more precisely. (note this isn't a proposal as such).
- source code continues to use module *names* only.
- define module *identifier* as (package name, module name) pair
- in the context of each module's source, there is assumed to be a mapping from module name to module identifier established by some external mechanism.
The "external mechanism" referred to here could be GHC's -package flags, or Cabal's build-depends, for example. For the purposes of the language definition, it doesn't matter.
Also, the Haskell module hierarchy is supposed to reflect functionality, whereas package names are purely administrative. This is a reason for not including package names in source code.
http://www.haskell.org//pipermail/libraries/2005-April/003513.html
My position on this has (still) not changed!
Cheers, Simon

"S. Alexander Jacobson"
Simon,
Right now, a module name in an import declaration identifies a module specification, a module name in a module declaration identifies an implementation, and some "external mechanism" resolves specifications to implementations. The big issue on the table here is what exactly this "external mechanism" should be. I'll suggest some requirements:
1. It should require minimal work for a user to share an implementation.
Unfortunately, our existing module resolver mechanisms are severely inadequate here. Build-depends and -package both violate #1 because they both force users to create packages even to share standalone pure haskell modules.
That's not true. Of course a single standalone pure haskell module or a set of simple modules can just sit in your source tree or elsewhere on the search path, just as they always have. Also framing this as a "Cabal vs. Haskell" discussion where you claim that your opinion is the True Haskell Way is both unfair and annoying. A couple of point of clarity for anyone following this discussion: - Cabal doesn't require any changes or extensions to the Haskell language (it's not Cabal vs. Haskell!) - The packaging system pre-dates Cabal. Cabal was layered on top of the packaging system, and a newer, more robust packaging system was designed and implemented in GHC in order to support more. At this point, I hope no one is drawing information about Cabal from your posts. peace, isaac

1. It should require minimal work for a user to share an implementation.
Unfortunately, our existing module resolver mechanisms are severely inadequate here. Build-depends and -package both violate #1 because they both force users to create packages even to share standalone pure haskell modules.
That's not true. Of course a single standalone pure haskell module or a set of simple modules can just sit in your source tree or elsewhere on the search path, just as they always have.
Neither Build-depends nor -package support finding a naked implementation at an arbitrary location in the filesystem. Both only recognize modules that have been packaged. -i complies with #1, but it violates "the works over the Internet" requirement.
Also framing this as a "Cabal vs. Haskell" discussion where you claim that your opinion is the True Haskell Way is both unfair and annoying.
If the names annoy you, please suggest alternatives. I think they are descriptive of vastly different ways to understand a Haskell program. Under Haskell, the module is the starting point for understanding a program. Under Cabal, the Cabal file is the starting point for understanding a program (e.g. the main-is tag). With Haskell, the user select the modules to be used to resolve import statements. With Cabal, the author makes the selection (e.g. the build-depends tag). With Haskell, dependencies are between modules. With Cabal, they are between packages. You might have a good reason to favor one model or the other, but its pretty clear that they are different.
- Cabal doesn't require any changes or extensions to the Haskell language (it's not Cabal vs. Haskell!)
Yes it does! It requires that you understand Cabal to interpret a Haskell program. In particular, as noted above, it specifies that you can only reach modules through main-is tags in Cabal files. Further it specifies that import statements in those modules have no meaning independent of build-depends tags in those Cabal files.
- The packaging system pre-dates Cabal. Cabal was layered on top of the packaging system, and a newer, more robust packaging system was designed and implemented in GHC in order to support more.
Ok, I am not objecting to having a package system per se (see my prior post). I am objecting to having a package system with a build-depends tag that points to other packages and I think that Cabal is the name for such package system.
At this point, I hope no one is drawing information about Cabal from your posts.
To be precise, I am using Cabal to describe a program model not the details of a particular implementation of that model. I have no doubt that Cabal is a superb *implementations*. Now, although I am concerned is that it is a superb implementation of the wrong model, I am also hopeful that we will be able to reuse much of it when we shift to a better one. In any case, my goal in this discussion is to spur better understanding of the model. Please do not take any of my comments as a disparagement of any implementation. -Alex- ______________________________________________________________ S. Alexander Jacobson tel:917-770-6565 http://alexjacobson.com

"S. Alexander Jacobson"
1. It should require minimal work for a user to share an implementation.
Unfortunately, our existing module resolver mechanisms are severely inadequate here. Build-depends and -package both violate #1 because they both force users to create packages even to share standalone pure haskell modules.
That's not true. Of course a single standalone pure haskell module or a set of simple modules can just sit in your source tree or elsewhere on the search path, just as they always have.
Neither Build-depends nor -package support finding a naked implementation at an arbitrary location in the filesystem. Both only recognize modules that have been packaged. -i complies with #1, but it violates "the works over the Internet" requirement.
If build-depends or -package somehow took away the "-i" option, then it might be true that "they both force users to create packages even to share standalone pure haskell modules." But that's not the case. You are free to not use -package and you are free to not use build-depends and only use "-i". Nothing is forced on anyone. All you are saying is that "-package refers to a package."
Also framing this as a "Cabal vs. Haskell" discussion where you claim that your opinion is the True Haskell Way is both unfair and annoying.
If the names annoy you, please suggest alternatives.
How about the "Cabal / HC-PKG approach vs the Alex Jacobson approach"? It's much less loaded.
I think they are descriptive of vastly different ways to understand a Haskell program. Under Haskell, the module is the starting point for understanding a program. Under Cabal, the Cabal file is the starting point for understanding a program (e.g. the main-is tag).
No. Under Cabal, the .cabal file is the starting point for understanding a package. The source code is still plain-old Haskell.
- Cabal doesn't require any changes or extensions to the Haskell language (it's not Cabal vs. Haskell!)
Yes it does! It requires that you understand Cabal to interpret a Haskell program.
Cabal is layered on top of the language. It doesn't change the language. (snip)
In any case, my goal in this discussion is to spur better understanding of the model. Please do not take any of my comments as a disparagement of any implementation.
I'm not taking it like that. I'm trying to help clarify what I think are mischaracterizations on your part. peace, isaac

Isaac,
You are free to not use -package and you are free to not use build-depends and only use "-i". Nothing is forced on anyone. All you are saying is that "-package refers to a package."
I am looking for a module resolution mechanism that fulfills all the requirements I posted. Neither Cabal nor -package nor -i nor any combination of them does that. For example, neither individually nor in combination do they allow me to share a naked implementation over the Internet. And they fail on the measures to which I referred earlier as well. If you think some of my requirements don't need to be met that is fine. However, I don't think you can claim that they are.
I think they are descriptive of vastly different ways to understand a Haskell program. Under Haskell, the module is the starting point for understanding a program. Under Cabal, the Cabal file is the starting point for understanding a program (e.g. the main-is tag).
No. Under Cabal, the .cabal file is the starting point for understanding a package.
It is Cabal's main-is tag that defines the entry point for interpreting a program rather than Haskell's main function. It is Cabal's build-depends tag that determines the meaning of import statement rather than the Haskell source.
The source code is still plain-old Haskell.
With Cabal, the source code is plain-old Haskell PLUS the plain-old Cabal of the package that encapsulates it. And while I would agree that Cabal is not changing the *syntax* of Haskell source, it is most definitely changing its meaning. Do you seriously want to argue that the two models are equivalent? I think we should keep our eye on the ball here. The existing module resolution mechanisms are inadequate to our needs. Lets focus on building something that meets them. -Alex- ______________________________________________________________ S. Alexander Jacobson tel:917-770-6565 http://alexjacobson.com On Wed, 20 Apr 2005, Isaac Jones wrote:
"S. Alexander Jacobson"
writes: 1. It should require minimal work for a user to share an implementation.
Unfortunately, our existing module resolver mechanisms are severely inadequate here. Build-depends and -package both violate #1 because they both force users to create packages even to share standalone pure haskell modules.
That's not true. Of course a single standalone pure haskell module or a set of simple modules can just sit in your source tree or elsewhere on the search path, just as they always have.
Neither Build-depends nor -package support finding a naked implementation at an arbitrary location in the filesystem. Both only recognize modules that have been packaged. -i complies with #1, but it violates "the works over the Internet" requirement.
If build-depends or -package somehow took away the "-i" option, then it might be true that "they both force users to create packages even to share standalone pure haskell modules." But that's not the case.
You are free to not use -package and you are free to not use build-depends and only use "-i". Nothing is forced on anyone. All you are saying is that "-package refers to a package."
Also framing this as a "Cabal vs. Haskell" discussion where you claim that your opinion is the True Haskell Way is both unfair and annoying.
If the names annoy you, please suggest alternatives.
How about the "Cabal / HC-PKG approach vs the Alex Jacobson approach"? It's much less loaded.
I think they are descriptive of vastly different ways to understand a Haskell program. Under Haskell, the module is the starting point for understanding a program. Under Cabal, the Cabal file is the starting point for understanding a program (e.g. the main-is tag).
No. Under Cabal, the .cabal file is the starting point for understanding a package. The source code is still plain-old Haskell.
- Cabal doesn't require any changes or extensions to the Haskell language (it's not Cabal vs. Haskell!)
Yes it does! It requires that you understand Cabal to interpret a Haskell program.
Cabal is layered on top of the language. It doesn't change the language.
(snip)
In any case, my goal in this discussion is to spur better understanding of the model. Please do not take any of my comments as a disparagement of any implementation.
I'm not taking it like that. I'm trying to help clarify what I think are mischaracterizations on your part.
peace,
isaac

"S. Alexander Jacobson"
It is Cabal's build-depends tag that determines the meaning of import statement rather than the Haskell source.
Correct me if I'm wrong, but I think this statement is the core of your argument. However, it is untrue. The Haskell source does not now, and never has, determined the referent of an import statement. That has /always/ been external to the language. There was once a compiler (Freja) that permitted multiple modules to occur in the same source file, which is slightly closer to what you want. But all other compiler implementations have adopted a separate-compilation model, where the mapping of an import statement (to the source code that supplies those entities) is determined external to the source code of the importing module, whether by Makefiles, hmake, manual -I/-package flags to the compiler, Cabal, or some other mechanism. This is exactly the same as in other languages like C, Ada, etc. Apart from a self-contained program consisting of a single module, Haskell has always depended on an external specification (often implicit) of the mapping between module names and module implementations. Cabal does not change this - it just makes it more convenient to express what you want when there are large numbers of modules involved.
The existing module resolution mechanisms are inadequate to our needs. Lets focus on building something that meets them.
I do not think everyone agrees that the existing import resolution model is flawed. If you truly believe Haskell needs to be changed to make import resolution internal to the source code, then you need to demonstrate more clearly what is wrong with the status quo; to persuade us that something is broken. Regards, Malcolm

I think I must be communicating extremely poorly here, because I think you are interpreting me to be saying something largely opposite what I think I am saying.
The Haskell source does not now, and never has, determined the referent of an import statement. That has /always/ been external to the language.
Yes, that is precisely my point! My objection to Cabal is that it in fact DOES determine the referent of an import statement (build-depends). To be more precise, I believe that module names in import statements have a *denotational* meaning e.g Prelude refers to a set of functions defined in the Report and Data.List refers to a set of functions defined in the Standard Libraries. But that the *operational* meaning should be determined by the module user e.g. different compilers may operationalize Prelude and Data.List very differently. Cabal attempts to give the packager author control over operational semantics; control that belongs in the hands of the package user. However, if this control is to be in the hands of package users, it would be nice to have tools that help them find implementations consistent with the import declarations of the modules they want to use. Is this any clearer? -Alex- ______________________________________________________________ S. Alexander Jacobson tel:917-770-6565 http://alexjacobson.com On Thu, 21 Apr 2005, Malcolm Wallace wrote:
"S. Alexander Jacobson"
writes: It is Cabal's build-depends tag that determines the meaning of import statement rather than the Haskell source.
Correct me if I'm wrong, but I think this statement is the core of your argument. However, it is untrue. The Haskell source does not now, and never has, determined the referent of an import statement. That has /always/ been external to the language.
There was once a compiler (Freja) that permitted multiple modules to occur in the same source file, which is slightly closer to what you want. But all other compiler implementations have adopted a separate-compilation model, where the mapping of an import statement (to the source code that supplies those entities) is determined external to the source code of the importing module, whether by Makefiles, hmake, manual -I/-package flags to the compiler, Cabal, or some other mechanism. This is exactly the same as in other languages like C, Ada, etc.
Apart from a self-contained program consisting of a single module, Haskell has always depended on an external specification (often implicit) of the mapping between module names and module implementations. Cabal does not change this - it just makes it more convenient to express what you want when there are large numbers of modules involved.
The existing module resolution mechanisms are inadequate to our needs. Lets focus on building something that meets them.
I do not think everyone agrees that the existing import resolution model is flawed. If you truly believe Haskell needs to be changed to make import resolution internal to the source code, then you need to demonstrate more clearly what is wrong with the status quo; to persuade us that something is broken.
Regards, Malcolm _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

"S. Alexander Jacobson"
I think I must be communicating extremely poorly here, because I think you are interpreting me to be saying something largely opposite what I think I am saying.
Well I must admit several of us have been having difficulty understanding what your point is. But we seem to be getting nearer to it now. :-)
The Haskell source does not now, and never has, determined the referent of an import statement. That has /always/ been external to the language.
Yes, that is precisely my point! My objection to Cabal is that it in fact DOES determine the referent of an import statement (build-depends).
I can see why you might object, if that were the case, but Cabal does NOT in fact determine the referent! Cabal is just a convenient way of grouping together the denotational /interface/ of a large bunch of modules. The implementations of those modules can be replaced at any time, provided they still meet the interface. At least, for some compilers (Hugs, nhc98) this is true, so I figure it is true in general for the Cabal model, and indeed the Haskell model. I believe the real problem you are objecting to is that a highly optimising compiler like ghc (or indeed the new jhc) DOES NOT SOLELY RELY ON THE INTERFACES of imported modules when it compiles another library module that uses them. These compilers do all kinds of cross-module optimisation, and therefore know a lot more about the actual implementation of the lower modules than just function names and type signatures. Hence, you cannot rip-and-replace a lower module at will, without also recompiling all higher modules that depend on it. Again, to be clear, this is ONLY in certain optimising compilers.
To be more precise, I believe that module names in import statements have a *denotational* meaning e.g Prelude refers to a set of functions defined in the Report and Data.List refers to a set of functions defined in the Standard Libraries.
Yes, I can see the general idea here. Unfortunately, Haskell doesn't have a particularly user-accessible notion of denotational interface, unlike Ada for instance. I think it would be nice if Haskell 2 could allow the user to write explicit interfaces, including properties beyond mere type signatures - especially if there is good semi-automated verification support for those properties. (I thinking QuickCheck, Programmatica, Alfa...) That would make it easier to replace the implementation of a module by a "better" one whilst guaranteeing it still does the "same" thing. Regards, Malcolm

I can see why you might object, if that were the case, but Cabal does NOT in fact determine the referent! Cabal is just a convenient way of grouping together the denotational /interface/ of a large bunch of modules. The implementations of those modules can be replaced at any time, provided they still meet the interface.
The Cabal spec says: build-depends: package list A list of packages, possibly annotated with versions, needed to build this one, e.g. foo > 1.2, bar. If no version constraint is specified, any version is assumed to be acceptable. http://www.haskell.org/ghc/docs/latest/html/Cabal/authors.html I interpret "needed to build this one" as requirement rather than recommendation. So I interpret build-depends as determining the referent. Moreover, I think Simon does too. He proposes that we should lift the overlap restriction by having module names map to (cabal-package, module) pairs. To me, that only makes sense if build-depends is determining the referent. He acknowledges that a consequence of this is that you risk errors like "can't unify (package foo, M.T) with (package bar, M.T)"! I am arguing instead that all modules in all packages used by a program should share the same referent for M.T, that we need a mechanism for establishing that referent, and that build-depends doesn't do that. I feel like we may actually be on the same wavelength here. Exciting! -Alex- ______________________________________________________________ S. Alexander Jacobson tel:917-770-6565 http://alexjacobson.com On Thu, 21 Apr 2005, Malcolm Wallace wrote:
"S. Alexander Jacobson"
writes: I think I must be communicating extremely poorly here, because I think you are interpreting me to be saying something largely opposite what I think I am saying.
Well I must admit several of us have been having difficulty understanding what your point is. But we seem to be getting nearer to it now. :-)
The Haskell source does not now, and never has, determined the referent of an import statement. That has /always/ been external to the language.
Yes, that is precisely my point! My objection to Cabal is that it in fact DOES determine the referent of an import statement (build-depends).
I can see why you might object, if that were the case, but Cabal does NOT in fact determine the referent! Cabal is just a convenient way of grouping together the denotational /interface/ of a large bunch of modules. The implementations of those modules can be replaced at any time, provided they still meet the interface.
At least, for some compilers (Hugs, nhc98) this is true, so I figure it is true in general for the Cabal model, and indeed the Haskell model.
I believe the real problem you are objecting to is that a highly optimising compiler like ghc (or indeed the new jhc) DOES NOT SOLELY RELY ON THE INTERFACES of imported modules when it compiles another library module that uses them. These compilers do all kinds of cross-module optimisation, and therefore know a lot more about the actual implementation of the lower modules than just function names and type signatures. Hence, you cannot rip-and-replace a lower module at will, without also recompiling all higher modules that depend on it. Again, to be clear, this is ONLY in certain optimising compilers.
To be more precise, I believe that module names in import statements have a *denotational* meaning e.g Prelude refers to a set of functions defined in the Report and Data.List refers to a set of functions defined in the Standard Libraries.
Yes, I can see the general idea here. Unfortunately, Haskell doesn't have a particularly user-accessible notion of denotational interface, unlike Ada for instance. I think it would be nice if Haskell 2 could allow the user to write explicit interfaces, including properties beyond mere type signatures - especially if there is good semi-automated verification support for those properties. (I thinking QuickCheck, Programmatica, Alfa...) That would make it easier to replace the implementation of a module by a "better" one whilst guaranteeing it still does the "same" thing.
Regards, Malcolm _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Cabal is just a convenient way of grouping together the denotational /interface/ of a large bunch of modules. The implementations of those modules can be replaced at any time, provided they still meet the interface.
build-depends: package list A list of packages, possibly annotated with versions, needed to build this one, e.g. foo > 1.2, bar. If no version constraint is specified, any version is assumed to be acceptable.
I interpret "needed to build this one" as requirement rather than recommendation. So I interpret build-depends as determining the referent.
"Needed to build" tells me which interfaces must be available at compile-time, no more and no less. I found recently that ghc-pkg (whose input format is essentially Cabal+extras) has a separate "builds" field, which maps the interfaces given in the "build-depends" field to a set of specific implementations. So the referent is (potentially) determined separately from the interface. Your confusion probably arises because there is no really hard separation between interface and implementation in the Haskell'98 source language. As it happens, different compilers blur the boundary between interface and implementation to a greater or lesser extent. But that's a compiler issue, not something intrinsic to either the language or to Cabal. OK, maybe you could complain that the language spec should be more explicit about interfaces, and I might be inclined to agree. (Versions 1.0 and 1.1 actually mentioned interface files, but they were deleted in 1.2, long before the '98 standard.)
Moreover, I think Simon does too. He proposes that we should lift the overlap restriction by having module names map to (cabal-package, module) pairs.
Well, the overlap restriction exists in the language already. If you want to lift it, you really need to change the language. Simon's proposal (which I support) is a hack to permit the restriction to be lifted without changing existing code, by re-interpreting all module imports to have an implicit (disambiguating) prefix. It is just an engineering tradeoff to ensure that huge mounds of legacy code are not broken purely for the sake of some rather rare overlap case. I think, even with the lifting of the overlap restriction, it will still be the base that certain compilers could permit the remapping of (package-version-module) identifiers to implementations. The version uniquely identifies the interface, not necessarily the implementation. Of course, in that situation, it starts to become complicated, because then you will want separate identifiers/versions for different implementations that match a particular (version of the) interface. Regards, Malcolm

Hi there, Malcolm wrote:
There was once a compiler (Freja) that permitted multiple modules to occur in the same source file, which is slightly closer to what you want.
I'm amazed that you remembered that! Anyway, the point of the Freja design was to have absolutely no assumptions about any correspondence between module names and file names: not in the language design, and not anywhere in the compiler implementation or supporting tool chain. So Freja is actually even more extreme than most current implementations, I'd say. (I just never liked the idea of having the module names, hierarchical or not, forcing the adoptation of any specific file names and directory structure.)
But all other compiler implementations have adopted a separate-compilation model, where the mapping of an import statement (to the source code that supplies those entities) is determined external to the source code of the importing module,
Well, Freja was the same. The reason for its capability to compile more than one module at a time was to deal with recursive modules, not that it was incapable of separate compilation. The idea was that an external make-like tool would be told about ALL source files. It would then figure out the dependences between the modules contained in those source files, group them into strongly connected components, and then invoke the compiler on individual files or group of files as appropriate, along with the interface files of previously compiled modules on which the modules currently being compiled depended. Thus the compiler would always get the names of ALL relevant files, source files and interfaces, from an external entity, and thus it wouldn't need to know much if anything about module/file naming conventions, any OS-specific restrictions on file names, or organization of the source hierarchy. I still think it was a pretty nice and simple design. But it never got completely implemented. Best regards, /Henrik -- Henrik Nilsson School of Computer Science and Information Technology The University of Nottingham nhn@cs.nott.ac.uk This message has been checked for viruses but the contents of an attachment may still contain software viruses, which could damage your computer system: you are advised to perform your own checks. Email communications with the University of Nottingham may be monitored as permitted by UK legislation.

"S. Alexander Jacobson"
With Haskell, the user select the modules to be used to resolve import statements. With Cabal, the author makes the selection (e.g. the build-depends tag). With Haskell, dependencies are between modules. With Cabal, they are between packages.
I don't think that is strictly true - or at least it is true only of the current ghc implementation. In nhc98 at the moment, if package foo build-depends on package bar, then the only requirement is that interface files for bar must be available when foo is built. You can change the implementation of bar at any time after that with no dire consequences, provided only that the interface has not changed. Regards, Malcolm
participants (5)
-
Henrik Nilsson
-
Isaac Jones
-
Malcolm Wallace
-
S. Alexander Jacobson
-
Simon Marlow