| « F# - Things I learned today | Vista spooling/printing delay - new problems » |
F# - The thing with the namespaces
18/03/08
F# - The thing with the namespaces
I just spent a little while hunting down an interesting problem in a little F# app. I had a bunch of code in a single file and I was going to structure it a bit and move certain parts into separate files. I started out from some code like this:
namespace Sturm.MyNamespace
type ICommandLine = begin
abstract member Parts: string list
end
type IPlugin =
abstract member CanHandle: ICommandLine -> bool
abstract member Handle: ICommandLine -> unit
type blah =
val mutable dummy: int
interface IPlugin with
member x.CanHandle(commandLine) = false
member x.Handle(commandLine) = x.dummy <- 1
end
new() = { dummy = 0 }
Yeah, I know - useless code. The point is that there are dependencies between the three types. So I was trying to move the interfaces into a different file, and suddenly the type blah couldn't find the interfaces anymore. Interesting.
The solution to this is simple, but looks a bit stupid. At the start of my new file, I had of course repeated the namespace declaration namespace Sturm.MyNamespace, but that is not enough. Even though that puts all the types in the same namespace, it is still necessary to explicitely open the namespace as well, if you're going to access elements that have been defined elsewhere for the same namespace. So I need this header in the file with the class type:
namespace Sturm.MyNamespace open Sturm.MyNamespace
While I can see the logic behind that, it doesn't seem like a very useful approach... perhaps I'll figure out the reasons later, right now I'm glad I've found a solution.
7 comments
Out of curiosity, what got you interested into F# ?
Is it for XPO / XAF ?
Regards,
Marc
That said, "does it make sense" is a bit of a weird question. I believe that F# is generally a more powerful language than C#, and so yes, it makes sense to use the most powerful language for most tasks. Would I start a new project in it today? Yes, I probably would. Would I go back and rewrite something that exists, for a perceived benefit? In most cases, probably not, since the benefit wouldn't justify that. But I'd probably try to use F# for additions to an existing core - .NET makes this easy. Whether or not these approaches are actually considered today, in 2008, in many development teams, depends on yet another set of conditions...
I've probably not looked into all the issues that might come up, but at least there'd be some questions to answer before one could consider using F# for a general purpose library that needs to be reused from other languages. In this situation, more often than one we find ourselves using the least common denominator only.
<a href="http://msdn2.microsoft.com/en-us/magazine/cc164244.aspx" title="F# Primer: Use Functional Programming Techniques in the .NET Framework">
First I had 'namespace Company.Product' which defines my window class and was referenced by main.fs. No problems.
When splitting off my graphics from the window into 'namespace Company.OpenGL' I lose ANY way to reference this new namespace from the window file (the other namespace). Out of only three files, file2 can never seem to reference file3 no matter how I swap or rename namespaces.
The only way I've been able to compile since then is by moving my application loop (only thing in file one, main.fs) back to mainwindow.fs, removing any namespace declaration there which then allows me to reference the OpenGL ns. Worst of all, it feels like VS2008 really needs a close solution/open solution when changing these namespaces before it properly recognizes them. Finally, the code works in FSI as well, but only, I think, because I am able to use "#load "Opengl.fs"".
<b>So my questions are:</b> do F# namespaces work differently than C# ones? Why can't two files in different parts of the same NS reference each other (X.Y can use 'open X.Z' and call Z's members)?
I can't specifically remember rules for C# NSes because they are so easy to use. For instance, in the example above, I never declared a Company namespace. So Oliver, when I try your trick in Company.Product, I get a "The namespace of module 'Company' is not defined" when I use "open Company.Product". This is error is technically true but changes the NSes to fix it doesn't solve the problem. In C#, for files in the same project, I'm pretty sure I can declare any NS and reference it with 'using' from any other file in that project without fail.


