- What's the difference between a module and a namespace?
Modules
Ok, let's start with the concept of a module. Here's the official Microsoft documentation on the topic: https://msdn.microsoft.com/en-us/library/dd233221.aspx. I found this particularly enlightening:
It [module] is implemented as a common language runtime (CLR) class that has only static members.
So think of it in the context of C# and it would look something like this:
class Blah
{
public static void Foo() { Console.WriteLine("Foo!"); }
}
That's a totally familiar concept, and it would look something like this (?) in F#:
module Blah
let Foo = fun () -> printfn "Foo!"
ASIDE: This example has brought up a new question, and something I stumbled over. Why doesn't this work?
let Foo = printfn "Foo!"
The reason is because this is actually setting Foo to the result of printfn "Foo!", which is val it : unit = (). So we need to make it clear that we're setting Foo to be a function, provided by the fun keyword, otherwise the compiler doesn't understand. This isn't a problem when you provide parameters, because the compiler can infer that you're creating a reference to a function.
UPDATE: Okay, as I've continued to learn I've gotten some more insight on this behavior. So the easier, possibly more "proper" way to do this is to use unit to represent the missing parameter:
let Foo () = printfn "Foo!"
UPDATE: Okay, as I've continued to learn I've gotten some more insight on this behavior. So the easier, possibly more "proper" way to do this is to use unit to represent the missing parameter:
let Foo () = printfn "Foo!"
This looks suspiciously like a function definition from a non-functional language, but it's not. And when you call the function, you've got to pass a unit as a parameter or it thinks you're just referencing the function:
// Not calling the function, just referring to it
Ok, back to modules. There are apparently two kinds of module declarations: top level and "local":
// Not calling the function, just referring to it
> Foo;;
val it : (unit -> unit) = <fun:it@117-30>
// Function call taking a parameter of type unit!
> Foo ();;
Foo!
val it : unit = ()
Ok, back to modules. There are apparently two kinds of module declarations: top level and "local":
- Top level declarations mean that the whole file is in the module. The module declaration also needs to be the first declaration in the file.
- Local modules means that you can have more than one module in a file. It's a little different than the top level module.
//Notice the identation!
module Blah1 =
let Foo = fun () -> printfn "Foo!"
module Blah2=
let Foo = fun () -> printfn "Foo2!"
I think that makes sense. Next rule:
- If you don't use a top level module declaration, F# will insert one for you with the same name as the file, first letter uppercased. However, it will only do this if:
- You're creating an exe and not a dll.
- You've got a single file.
- You're not including the file as a library.
- So basically, if you're making a library you have to create a top level module or namespace.
I tripped over this rule when I tried to import a file in the REPL in a previous post. I had to go in and add a module declaration, remember?
Apparently you can also set an accessibility modifier, but I'm not going to mess with that right now.
Modules can also nest. So this is legal:
//Notice the identation!
module Blah1 =
let Foo = fun () -> printfn "Foo!"
module Blah2=
let Foo = fun () -> printfn "Foo2!"
You should also notice that we've got the function Foo in Blah1 and again in Blah2. These are distinct Foos since they're in different modules and there's no name collision.
Alright, so I think I'm getting the hang of modules. Now...
- What's the difference between a module and a namespace?
No comments:
Post a Comment