Why does F# allow attributes that don't inherit from System.Attribute? - f#

I created an F# 'Nunit' project using a template in VS 2019 to do some testing, and the default fixture code it created was the following:
namespace Tests
open NUnit.Framework
[<TestClass>]
type TestClass () =
[<SetUp>]
member this.Setup () =
()
[<Test>]
member this.Test1 () =
Assert.Pass()
It's an otherwise ordinary looking class, except the curiosity on the class declaration. I expected to see [<TestFixture>], but instead I see [<TestClass>], the same name as the auto-generated type. I suspect that this is a bug in the project template, but strangely, F# will happily compile this, with a note that it probably won't be compatible with other .Net languages:
warning FS3242: This type does not inherit Attribute, it will not work correctly with other .NET languages.
crystal clear for me. My question is, why does F# even allow this? Do the reflection capabilities in .Net even work for such an attribute in F#? What would a potential use-case be?

Historically the check was forgotten to be added to the compiler. When it was discovered, I propose to make it compilation error, but it ended up as a warning for backward compatible reasons. See https://github.com/Microsoft/visualfsharp/pull/5192 and https://github.com/Microsoft/visualfsharp/pull/5610 for details.

Alas, I do not have the answer to the question why F# allows this. A quick experimentation shows that using ordinary classes as attributes works - at least in a very basic situation:
type A(n:int) =
member x.N = n
[<A(10)>]
type B() = class end
(typeof<B>.GetCustomAttributes(true).[1] :?> A).N

Related

Is the FSharp.Data XML type provider generative or not?

(previously "using type provider from C#")
This should be easy to answer, and the underlying issue has be asked before, but I'm slightly confused about it, having dug into it, there's something I'm missing.
The Xml type provider in
https://fsharp.github.io/FSharp.Data/library/XmlProvider.html
is erased?
so the types in it can't be used from another assembly?
"Erasing Type Providers produce types that can only be consumed in the assembly or project they are generated from" (says the MS docs).
but if I define in one assembly this
module Xml
type Xml = FSharp.Data.XmlProvider<"""
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>""">
let foo () = Xml.Parse ("")
and in another assembly, reference the above assembly and go...
let x = Xml.foo ()
let s = x.From
this compiles...so if the MS docs are correct, the provider must be generative?
if I implement the same code in C#,
var x = Xml.foo();
var y = x.From;
then this code doesnt compiler
'XmlElement' does not contain a definition for 'From' and no accessible extension method 'From' accepting a first argument of type 'XmlElement'
which seems to imply its erased...or I need to do something else (I've included the same dependencies).
My hunch is its erased, but then how does the F# assembly compile?
(I want it to be generative to use from C# and VB).
As far as I can tell by looking at the source code, all the types provided by FSharp.Data are erased.
The XmlProvider type is defined by this line at https://github.com/fsharp/FSharp.Data/blob/master/src/Xml/XmlProvider.fs#L26
let xmlProvTy = ProvidedTypeDefinition(asm, ns, "XmlProvider", None, hideObjectMethods=true, nonNullable=true)
As you can see, the instantiation of the ProvidedTypeDefinition type does not include isErased=false.
The ProvidedTypeDefinition type has two constructors. See the signatures at https://github.com/fsprojects/FSharp.TypeProviders.SDK/blob/master/src/ProvidedTypes.fsi#L268-L275
Both constructors have an implementation including this line, which means that the provide type is erased by default:
let isErased = defaultArg isErased true
Without redesigning the XmlProvider, the only way you can consume it from C# is to wrap it in an F# class that exposes C#-friendly types. Not sure if that would result in a better design than just avoiding the type provider altogether.
Assuming by "erased" you mean being removed from the FSharp.Data Library? then XMLProvider its probably not removed from it because I just tried your code and it works in F# project (as you have also noticed).
Now about the C# project the thing is TypeProviders are a Fsharp specific thing, whatever magic F# compiler is doing to type check xml and access the From xml-node here is probably only exclusive to F#.
The type of you variable x here is FSharp.Data.Runtime.BaseTypes.XmlElement, looking at the documentation here and the source code here.
There doesn't seem to be any way of accessing the xml nodes in an OOP way. Its probably not meant to be accessed that way either. If you want to parse xml and read its nodes in C# there are plenty of other ways for that. One being XmlReader in System.Xml

How to define a ref struct in F# in .NET Standard 2.0?

When F# 4.5 was announced, it was stated that:
The F# feature set is comprised of
[...]
The ability to produce IsByRefLike structs (examples of such structs: Span<'T>and ReadOnlySpan<'T>).
How to "produce" these types? I tried the [<IsByRefLike>] attribute but is was not found in .NET Standard 2.0.
The attribute is found in System.Runtime.CompilerServices
open System.Runtime.CompilerServices
[<Struct; IsByRefLike>]
type Apa =
{ A: Span<int>
B: int }
Phillip Carter talks about this in What's new in F# 4.5 (about 21 min. in).
It is available for .NET Core and .NET Framework, but not .NET Standard 2.0.
Starting with .NET SDK 6.0.200 (available in Visual Studio 2022 17.1), the F# compiler recognizes user-defined IsByRefLikeAttributes. The following code will transparently enable defining ref structs on .NET Standard 2.0 as well as later frameworks:
#if NETSTANDARD2_0
namespace System.Runtime.CompilerServices
open System
[<Sealed; AttributeUsage(AttributeTargets.Struct)>]
type IsByrefLikeAttribute() = inherit Attribute()
#endif
namespace MyLibrary
open System
open System.Runtime.CompilerServices
[<IsByRefLike>]
type MyRefStruct(span: Span<int>) = struct end
Technically, this is not an answer.
First, according to the specs, IsByRefLike is for the compiler, not for the developers to use: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.isbyreflikeattribute?view=netframework-4.7.2
Second, when we do want something from a compiler, then it is crucial that we do understand what we want from it. So a correct question could be: I need ABC because I need to do XYZ, where ABC would be something related to IsByRefLike and then XYZ would be something based on IsByRefLike. The question does not explain why IsByRefLike is needed.
I think that a minimalist approach should be always weighted in when considering which language features to use / not to use: do we really need some particular language feature to accomplish what we need? F# Option.bind comes to mind: if the function is a one-liner then Option.bind is great. However, if there is some tree of how to parse the result, then it might be better to do that explicitly without using Option.bind.
So the questions are:
Do you really need IsByRefLike?
If you think that you do, could you, please, post an example of where you actually do need it.

Delay the implementation of interface methods?

I've been programming in F# for some years and there's an "issue" that's been bothering me for some time and I have not been able to solve. It is not a bug, I think it is a design decision, but anyway, the problem is this: is there a way to delay (maybe that's not the correct word for this) the implementation of interfaces?, that is, not implementing them in the initial definition, but later, maybe in the same file after I have implemented a module for the type. I'll explain with a simplified example:
Suppose I have the following data structure:
type 'T MyCollection =
(*type definition*)
interface IEnumerable<'T> with
member this.GetEnumerator () =
(* I don't want to implement it here
because I still don't have the module
with a toSeq function *)
If I implemented the method right there, I would have to also implement all the functions as methods of the type and then the module would be just a "proxy" for calling the methods. This way I'm creating a OO-first data structure and then creating a module (overloaded with type annotations) to allow for a functional-first usage. I would prefer to write a functional-first data structure (cleaner since the type inference can work better) and then create a OO wrapper to allow a better intellisense support for languages like C#. That approach complies with what the design guidelines for F# tells us, but the interfaces can't be implemented anywhere but in the initial definition of the type. That restriction forces me to write the whole data structure with members.
I've been looking for examples and I've found that the list implementation in FSharp.Core list does exactly what I want, but I can't do that, the compiler won't let me.
I'm almost sure that this is a design decision, maybe to avoid encouraging bad practices, I don't know, but I don't consider my wish to be a bad practice. Also I'm well aware of the linear nature of the fsharp compiler.
Please if any of you know how to do what I want, I'll be glad if you tell me. Also, if any of you know why I should not follow this approach I'll be glad to know too. There must be a reason why this is not a problem for anyone else.
Thanks in advance.
I completely agree that this is unfortunate problem. The trick that is used in the source code of 'a list in the F# Core library is to define the implementation of the interface in a type augmentation. The compiler does not complain when you add members to a type in this way, but it says that adding implementation of an interface in this way is deprecated. However, it does not prevent you from doing this. The following compiles fine for me:
open System.Collections
open System.Collections.Generic
type MyCollection<'T> =
{ Data : 'T list }
interface IEnumerable<'T>
interface IEnumerable
let getEnumerator { Data = d } =
(d :> seq<_>).GetEnumerator()
type MyCollection<'T> with
interface IEnumerable<'T> with
member this.GetEnumerator() = getEnumerator this
interface IEnumerable with
member this.GetEnumerator() = (getEnumerator this) :> _
The fact that this is deprecated is a bit unfortunate. I quite like this style and I use it when it makes sense. You can start a discussion about this on F# user voice and perhaps it could be turned back into a normal accepted feature :-)

"new" keyword causing red squiggle

I wonder what's going on here...
I just created a new, empty F# Console application in Visual Studio 2013 (using F# 3.1 and .NET 4, FSharp.Core Version 4.3.1.0) and added the Reactive Extensions Main Library using Nuget: Install-Package Rx-Main
Now check this out:
This works and the hovering over test shows val test: unit -> System.Reactive.Subjects.Subject<'a>. As expected. Then I added the new keyword.
Interesting. Does anybody know why adding the new keyword breaks the code? For reference, if you additionally specify the type parameter, it works:
I can't find a spec reference off-hand, but when using new explicit type args are required. You need to do:
let test() = new System.Reactive.Subjects.Subject<_>()
It appears to be a static class, and static classes cannot be newed up.
http://msdn.microsoft.com/en-us/library/system.reactive.subjects.subject%28v=vs.103%29.aspx
And to elaborate on your specific error message, it means there is public no constructor available that accepts 0 parameters. As far as I know, static classes only have private, parameterless constructors.

When making a test class with FsUnit, [<Test>] is not a valid attribute on a member. Why?

I'm fiddling with a new F# project (of which I haven't made many), and I'm aiming to do it in a TDD fashion. So, I'm trying to familiarize myself with using FsUnit, since I have a lot of experience using NUnit in C# projects, and it seems a pretty common framework to use.
My code looks like the following:
module DatabaseReaderTest
open NUnit.Framework
open FsUnit
[<TestFixture>]
type DatabaseReaderTest ()=
[<Test>]
member x.ResultsAreReturnedFromDatabase =
DatabaseReader.result.GetSqlString(1) |> should equal "first"
As far as I can tell, this follows the example on the FsUnit home page (http://fsunit.codeplex.com/), but the compiler tells me that [<Test>] is not a valid attribute on this language element, by which I assume it means member.
Any tips on what I'm doing wrong here?
Thanks!
You probably need to use a method rather than a property. Just add a () argument of type unit.
As a side-note, if you don't need any custom initialization before tests are run and if you're using a recent version of NUnit, then you should be able to use module with let bound functions for your tests.
This gives you a bit more lightweight syntax. Some people also like to use double-tick syntax that makes it possible to write the test name as an ordinary English sentence (which shows nicely in test runner):
module DatabaseReaderTest =
[<Test>]
let ``Results are returned from database`` () =
DatabaseReader.result.GetSqlString(1) |> should equal "first"

Resources