This works
open System
let f = Action(fun () -> Unchecked.defaultof<_>)
But this
let f = System.Action(fun () -> Unchecked.defaultof<_>)
produces the compilation error
Multiple types exist called 'Action', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. 'Action<,,_,,,_,,,_>'.
I know I can fix it by adding a type parameter placeholder (System.Action<_>(...)), but any idea why they behave differently?
EDIT
Found this in the spec, section 14.1.9:
When a module or namespace declaration group F is opened, items are added to the name environment as follows:
Add the type to the TypeNames table. If the type has a CLI-mangled generic name such as List'1 then an entry is added under both List and List'1.
Is this behavior replicated for fully-qualified types (with omitted type parameters)? It doesn't appear so.
I agree with #James that this is related to the bug submitted on Connect, but I think it is a slightly different case. Anyway, I think this is not the intended behaviour. Could you report it to fsbugs at microsoft dot com?
Anyway - I did some debugging and here is what I found so far:
It seems that the compiler uses different code paths to resolve the name Action and the name System.Action. When resolving the other, it searches all loaded modules (i.e. assemblies) for a type named System.Action (see ResolveLongIndentAsModuleOrNamespaceThen function in the nameres.fs file of the open-source release).
This finds the two definitions of Action (one in mscorlib and another in System.Core). I think the issue comes from the fact that the name resolution simply iterates over the results - it finds the first one (from System.Core), which doesn't have a usable overload (because it ranges from Action<_,_,_,_,_> to a version with about 15 type parameters). After finding this type, it reports an error without even looking whether there is another type (in another assembly) that could be used.
If you don't reference system assemblies, then the F# compiler resolves the overload just fine. Running the compiler without parameters references the default assembly set, so this doesn't work:
fsc test.fs
but if I add the --noframework flag, then it compiles without issues:
fsc --noframework test.fs
Related
I have a F# custom type provider (in this case CheckedRegexProvider); the relevant source is
[<TypeProvider>]
type public CheckedRegexProvider() as this =
inherit TypeProviderForNamespaces()
// Get the assembly and namespace used to house the provided types
let thisAssembly = Assembly.GetExecutingAssembly()
let rootNamespace = "Samples.FSharp.RegexTypeProvider"
let baseTy = typeof<obj>
let staticParams = [ProvidedStaticParameter("pattern", typeof<string>)]
let regexTy = ProvidedTypeDefinition(thisAssembly, rootNamespace, "RegexTyped", Some baseTy)
do regexTy.DefineStaticParameters(
parameters=staticParams,
instantiationFunction=(fun typeName parameterValues ->
match parameterValues with ...
Then I have a simple test project where I put some trivial code in a .fs
open Samples.FSharp.RegexTypeProvider
type T = RegexTyped< #"(?<AreaCode>^\d{3})-(?<PhoneNumber>\d{3}-\d{4}$)">
What puzzles me is that the instantiationFunction gets called many more times than I expected. I thought that function would be called only when I changed the static parameters (in this case "(?^\d{3})-(?\d{3}-\d{4}$)"), instead every time I do something in the test source (e.g. push the space bar), that lambda gets called twice consecutively. If I really change the parameter, it gets called twice or three times.
This of course has quite an impact on the IDE (in my case Visual Studio), especially because that function is meant to provide a type that likely requires to scan some data source for schema information.
I then tried to isolate the type provider invocation in a separate source module file (let's call it M1.fs), and open that module in the actual test code (M2.fs). With this, the lambda gets still called at every touch of M1.fs, but it's not called at all when I work in M2.fs, as expected.
What I am asking is: are those continuous re-calls to the instantiation function correct? Is that by design?
And if yes, why is that so?
Type providers are called at compile time, and the compiler then uses the types that they provide in compiling the rest of the code.
Nearly every IDE that handles F# code intelligently does so by calling the F# compiler service behind-the-scenes to build an AST (usually one source file at a time), and then does operations on that AST for things like providing Intellisense.
The F# compiler service does not cache the results of previous compilations, because any change you make may have effects elsewhere in the source file, both before and after it. The "after" part of that statement is for obvious reasons, but it may not be immediately obvious why a change in line 25 could affect line 10. The reason for that is type inference: if line 10 is let a = Array.zeroCreate 1024, and line 25 is a.[0] <- 42, then the type of a will be inferred to be int[]. If you change line 25 to a.[0] <- "forty-two", then the type of a will be inferred to be string[], and the AST built for line 10 will be different. Therefore, the F# compiler service re-compiles the entire source file every time it's called.
Therefore, every time you edit your source file, the F# compiler service re-compiles the file. If that file is the one that includes your type provider definition, the compiler has to instantiate the type provider in order to compile the file, and so your instantiationFunction has to be called every time the file is compiled.
So yes, the behavior you're seeing is by design.
I just started to study F# and accidentally wrote this binding
let List = 1
Now when I try to obtain List methods such as 'filter' I get this error
error FS0039: The field, constructor or member 'filter' is not defined.
Of course using method with full type name like Microsoft.FSharp.Collections.List.filter is still working.
I'm wondering why it is possible to use type name as identifier in F# and how I can set back name List to type List from Microsoft.FSharp.Collections.
When I tried to reassign like this
type List = Microsoft.FSharp.Collections.List<'T>
I get
Error FS0039: The type parameter 'T is not defined.
Thank you!
In F# you can redefine almost everything and shadow existing definitions. This applies to both types (well actually types have a different behavior regarding shadowing, they shadow their values as you open the namespaces) and values but not interchangeably since values and type (and also modules) can somehow coexist at the same time in the scope. The compiler will do his best to find out which one is.
You are not forced to, but it's a common good practice in F# not to use let bindings in uppercase.
Regarding your second question, you are using a type parameter in the right side which doesn't exist in the left side of the assignment, it should be:
type List<'T> = Microsoft.FSharp.Collections.List<'T>
But notice that filter doesn't belong to the type. It's rather defined in the List module.
You should just rename your let binding from List to something sensible - as Gustavo mentioned, your definition is shadowing the core List module from F# and there is no way to use List to refer both to your integer and to the module. Shadowing core functions will make your code pretty confusing. It's also a good idea to use camelCase for let bindings, but that's a matter of taste.
If you insist on shadowing List, then you won't be able to call List.filter using List.filter. If you wanted something shorter, you could define module alias:
module FsList = Microsoft.FSharp.Collections.List
Note that your attempt to do something similar with List<'T> does not do the same thing, because functions such as filter are in a module named List rather than being static members of the type. With this, you can call filter using FsList.filter.
I have a union type that has a single, empty case.
type Default =
| Default
This type has a purpose, but it's not meant to be visible or usable.
Unfortunately, I have to use it in an inline function that does need to be visible. This prevents me from making the type or the case private.
The solution I came up with is using the CompilerMessageAttribute on it to signal an error whenever it's used. This would be fine, but now I can't compile my own assembly because IT uses it.
Is there a way to signal an error only when it's used by an assembly that references my assembly?
Let me reiterate the requirements to make sure I understand them:
The type needs to be public, so that that other assemblies can reference it implicitly via inline.
But if other assemblies reference it explicitly, then that is an error.
I don't know of any way of doing this using standard tooling.
I can see two possible solutions.
If only one calling assembly needs to use the inline function, what about making the type internal and then have the calling assembly be a friend assembly, using the InternalsVisibleToAttribute.
The only other alternative I can think of is security by obscurity. Hide the type in some awkwardly named module and require module qualification. This will stop accidental use of the type, if nothing else.
You could even add a build step to check that no source code references the module name.
[<RequireQualifiedAccessAttribute>]
module ``Dont Use This`` =
type Default =
| Default
let x = ``Dont Use This``.Default
And yes, it's very kludgy.
I have a name clashing problem while opening some .Net assemblies in my F# code using
open System.IO
The only option I found and use now is to provide the full names of types for conflicting types, but this is a little bit boring.
Is there any possibility to define an alias for .Net namespace in F# to prevent name clashing?
F# does not support aliasing of namespaces - only modules and types. So, to resolve the conflicts between .NET assemblies, you will, unfortunatelly, need to define aliases for all the types you're using.
This may be slightly easier thanks to the fact that F# type aliases are viewed as normal type declarations (by the F# compiler, not by the runtime). This means that, unlike with C# using keyword, you can define them in a spearate file:
// Aliases.fs
namespace SysIO
// Open the 'System' namespace to get a bit shorter syntax
// ('type File = File' is interpreted as discriminated union)
open System
type File = IO.File
type Directory = IO.Directory
In the rest of your application, you can now use SysIO.File. You still have to write the aliases, but at least you don't have to do that in every file...
I encountered a strange compiler error in Delphi Prism 2010 that I am unable to resolve. The error is calling a method on an object defined in a third-party assembly that manipulates a specialized image format. The assembly itself was compiled against the .Net 2.0 Runtime.
Despite providing the correct list of parameters, I consistently get an error and series of warning messages indicating the parameter list is incorrect. The VS 2008 IDE also refuses to perform parameter completion, yet correctly shows the method prototype and allows the method to be added using Ctrl-Space. Below is an abbreviated version of the compiler errors to illustrate the problem:
Error 1 (PE19) There is no overloaded method "GetTempMapOfIRSensor" with these parameters
Warning 2 (PH2) Best matching "Image.GetTempMapOfIRSensor(var rectOnSensor: System.Drawing.Rectangle; out average: System.Double; out minTempArrayIndex: System.Int32; out maxTempArrayIndex: System.Int32; desiredTempUnits: Image.TEMP_UNIT): array of System.Double" doesn't match on parameter 1, parameter is "System.Drawing.Rectangle" should be "System.Drawing.Rectangle"
Warning 3 (PH2) Best matching "Image.GetTempMapOfIRSensor(var rectOnSensor: System.Drawing.Rectangle; out average: System.Double; out minTempArrayIndex: System.Int32; out maxTempArrayIndex: System.Int32; desiredTempUnits: Fluke.Thermography.TEMP_UNIT): array of System.Double" doesn't match on parameter 2, parameter is "System.Double" should be "System.Double"
....a list of similar warnings for each remaining parameter
The strange part is that the compiler complains about a type mismatch for each and every parameter, yet the error message shows the parameter type names are the same (e.g. parameter is "System.Double" should be "System.Double").
Any suggestions on how to troubleshoot and resolve this issue would be welcome. The class in question, other than this one method, seems to work fine in every other respect. I am also able to create a method on the local class with the same signature and call it without error.
Update:
Invoking the method using reflection and the same parameter list works properly. This is looking to be a compiler bug/limitation of some sort.
If this library has overloads for non-var/out & var or out parameters with the rest of the signature the same, turn off the option for implicit out/var parameters and add out & var in the places they're needed. That should fix, else a QC entry generally is fixed quite fast, if it's a bug.