How to open one namespace from another within the same project? - f#

I'm trying to learn a bit of F#, coming from C#. I've got a new library project with two code files in it. Each code file is in a different namespace. I need to open one of the namespaces from the other file though. I don't seem to be able to actually open that other namespace, though. It's like it doesn't exist. Can anybody point out what I'm doing wrong?
Here's a screen shot of my project structure, for reference ...
LeagueTeam.fs:
namespace League.Entity2.Database
type LeagueTeam() =
member val Id = 0L with get, set
member val Name = "" with get, set
member val DateCreated = System.DateTime.Now with get, set
TeamGetByIdResponse.js
namespace League.Entity2.WebApi
open League.Entity2.Database
type TeamGetByIdResponse() =
member val Team = new LeagueTeam() with get, set
In the TeamGetByIdResponse.fs file, I need to set a property using the type from the LeagueTeam.fs file. So, when I try to open that namespace to use the type I get intellisense for League.Entity2 namespace, but I don't see the Database namespace used in the LeagueTeam.fs file. If I manually type in open League.Entity2.Database it says that the module League cannot be found.
Do namespaces work a bit differently in F# than C#?

Related

JSON Type provider with Saturn Framework `Controller.getModel<MyModel>` not working

I've some trouble getting my type to work with Saturn and the JSON type-provider.
My type: (generated by the typeprovider)
[<CLIMutable>]
type FeatureModel = JsonProvider<"../example.json">
My code in the Controller.create Action:
...
let! inputModel = Controller.getModel<FeatureModel> ctx
let uploadedName = inputModel.Feature.Name //Example
...
I would expect intellisense to work for inputModel.Feature.Name, but it doesn't. I've validated the type. If I use it directly with FeatureModel.GetSample() it does show me properties/fields.
Any idea what I'm missing or doing wrong?
you can't use CLIMUtable on a type provider, a that's an erased type (unfortunately).
[<CLIMutable>]
type FeatureModel = JsonProvider<"../example.json">
the above line shouldn't compile i think.
The resons is some type providers (Erased types) are erased at compile time, so they cannot be used by CLI (common language interface and runtime),
but you might have other ways to use those in controllers.
Maybe using some other custom serializers or Saturn, instead of using aspnectore controller binding directly, or creating your own custom binding.
else you could pass a raw string in the controller, and use FeatureModel.Parse inside of it (probably that works), as suggested above

Is there a way to import (open) specific functions in F#?

Instead of importing a whole module, is there a way to open specific functions in another module? Something like:
open TestFuncs with [myTestFuncInOtherModule]
As you can see in the docs, the open keyword doesn't actually load a module or namespace. It just allows you to refer to elements in that module/namespace without refering to their fully qualified name.
Being so, when you use open you're just making it easier to call the functions in that module, not actually importing/loading them in memory, so the short answer for this question is that using the open keyword you can't do this to only one function.
You can achieve the same thing easily with a let binding, though:
let f = TestFuncs.myTestFuncInOtherModule
It's not currently possible, but I've actually put in a request for this to be added to the language. If you want to see this added in F# 4.0, one thing you could do is go vote for that request.
Another good workaround, that hasn't been mentioned yet by other answers, is to "pseudo-open" modules: assign a short name to modules whose contents you want to use. Like so:
module TP = Microsoft.FSharp.Data.TypeProviders
type mySchema = TP.SqlDataConnection<"...">
let db = mySchema.GetDataContext()
This gives you the convenience of not having to type the whole module name every time you want to reference its contents, but you maintain control of your namespace: this way there's no chance of accidental name collisions when you update a module to a new version and it adds new names.
You can refer to particular functions in another module using full function name ModuleName.funcName:
module One =
let square x = x * x
module Two =
let anothersquare x = One.square x

Why is FSharp.Data.SqlClient record exposed as object?

I'm working on a demo where I can show how easy it is to use the SqlClient type provider in a F# library and then consume it from C#, I think this might be one way to get things into projects. Since many people using C# want to use interfaces etc. I thought I show them that it is possible to combine everything, but I don't get the expected result. I have the following F# code which works as expected in F#:
module Orders =
[<Literal>]
let connStr = """XXXXXXXXXXXX"""
type OrdersPerEmployee = SqlCommandProvider<"OrdersPerEmployee.sql", connStr>
open Orders
type IOrdersRepo =
abstract member getOrdersPerEmployee : int -> OrdersPerEmployee.Record seq
type OrdersRepo() =
interface IOrdersRepo with
member this.getOrdersPerEmployee(employeeId) =
let query = new OrdersPerEmployee()
query.Execute(employeeId)
But when I try to use it from my C# app I don't get that the getOrdersPerEmployee returns an enumerable of records, instead it returns an enumerable of objects:
IOrdersRepo repo = new OrdersRepo();
var data = repo.getOrdersPerEmployee(4).ToList();
data.ForEach(y => Console.WriteLine(y));
Console.ReadLine();
In the code above I expceted to get intellisense on y in the lambda, but nothing. Any ideas?
Because SqlCommandProvider is erasing types kind. It means types it generates can be consumed only from F#. Contrary, SqlEnumProvider from the same FSharp.Data.SqlClient library is generated types kind and can be consumed by C# (via proxy project). It works especially nice when CLIEnum=true.
For a deeper discussion on erased vs generated types see
How do I create an F# Type Provider that can be used from C#?

Intellisense not working for F# type provider

I've created a simple type provider that I want to expose some pre-generated types in an assembly, as follows:
[<TypeProvider>]
type TestProvider() as this =
inherit TypeProviderForNamespaces()
let providedType = ProvidedTypeDefinition(Assembly.GetExecutingAssembly(), "Test", "TypeLib", None)
do let assembly = Assembly.LoadFrom #"C:\Some\Long\Path\TestTypes.dll"
// Get same problem with providedType.AddAssemblyTypesAsNestedTypesDelayed(),
// which is what I really want to use
providedType.AddMember(assembly.GetType("TestTypes.Circle"))
this.AddNamespace("Test", [providedType])
I consume this provider from another project as follows:
// Circle member not showing up under TypeLib
type Circle = Test.TypeLib.Circle
let c = Circle()
c.Radius <- 4.
printfn "%f" c.Radius
System.Console.ReadKey() |> ignore
It compiles, runs, and works as expected, but for some reason the Circle doesn't show up in the Intellisense list for Test.TypeLib. Also when I hover over Circle it says A reference to type 'TestType.Circle' in assembly 'TestTypes' was found, but the type could not be found in that assembly.
What am I doing wrong?
UPDATE: As suggested by a Dmitry, I viewed the related question and downloaded the associated type provider that is trying to do something similar to what mine is doing. Unfortunately, on my machine that provider behaves the same as mine, i.e. it provides Intellisense for namespaces but not types. So I don't know if it could be something specific to my configuration or what.
Well, it wasn't my code. It turns out that when I use the exact ProvidedTypes-head.fs contained in the linked example, then everything works like it should. However, when I use a different version, like the ProvidedTypes.fs from FSharp.Data, then it has the incorrect behavior. I'm not sure what the difference is between them that is causing the issue. I'm also not sure where to find the "official" version of the the file, if one indeed exists.
UPDATE: Looks like the official version is here.

F# types or System types with ASP.NET MVC?

While building a F# ASP.NET MVC 4 app with the C#/F# template from the VisualStudio gallery, a doubt assaulted me. I have the following model class:
namespace MyApp.Models
open System
open System.ComponentModel.DataAnnotations
open System.Collections.Generic
type Product() =
[<Key>] member val Id = Guid.NewGuid() with get, set
[<Required>] member val Name = "" with get, set
member val Iban = "" with get, set
member val Categories = new List<ProductCategory>() with get, set
As F# has its own types, in cases like the last one, should we use an F# equivalent (an F# list, a sequence...) or should we use System types? If so, what would be the reasoning?
Thank you very much!
As a rule of thumb, I'd go by what language(s) is(are) consuming your models. If it's F# all the way down, go for it. If it's mixed you'll need to be more judicious. As an aside, Option<> and List<> play pretty well with C# (though I find I need type aliases to "clean up" some of the code). Also an F# sequence is just an IEnumerable<>, so no worries there. Also, there's nothing wrong with using arrays and ResizeArray<> (aka System.Collections.Generic.List<>) in F# -- you just have to be mindful of state mutation.

Resources