How to access static functions from inside a class member function? - f#

I have a unit test class:
type [<TestFixture>] BetTests()=
[<Test>]
member x.HasGoodOddsTest() =
let ret = HasGoodOdds 10.0
Assert.IsFalse(ret, "Expected false");
and a static method defined outside of the class:
let HasGoodOdds odds = odds >= 20.0
but I'm getting a compiler error: "The value or constructor 'HasGoodOdds' is not defined."
What's the syntax to get outside of the scope of the class? Thanks!

Is HasGoodOdds defined above the BetTests class? Is it defined in the same file?
It needs to be defined above it (in a prior file, or above it in this file - generally you can't reference entities in F# until after they are defined), and if the BetTests class is not defined in the same module, you need to either use a qualified name (as #Vitaliy says) or use an 'open' declaration to bring the namespace/module into scope.

This method should be defined in a module. Use Namespace.ModuleName.Method convention

Related

May static and non static variables in class have the same name according to DartLangSpec-v2.2

A class has several scopes:
• A type-parameter scope, which is empty if the class is not generic (14).
The enclosing scope of the type-parameter scope of a class is the enclosing
scope of the class declaration.
• A static scope. The enclosing scope of the static scope of a class is the
type parameter scope (14) of the class.
• An instance scope. The enclosing scope of a class’ instance scope is the
class’ static scope.
From https://dart.dev/guides/language/specifications/DartLangSpec-v2.2.pdf page 27
class Foo {
static var x;
var x;
}
I think according to the document it should work. But getting compilation error. Is my understanding about scope wrong? If I am wrong can you please clear me about the difference between scope and namespace in dart.
Scopes/name-spaces are pretty much as you expect. They are mainly used for lookups, not conflict resolution. Most conflict resolutions are handled explicitly in the specification in other places (although a few are just handled by the rule that you can't introduce the same name into a scope twice).
For example, there are more restrictions on classes than just the scope based ones, including:
A class must not declare two members with the same basename unless one is a setter and the other is a getter.
A class must not declare a static member with the same basename as an inherited member.
A class must not declare a type parameter with the same name as the class.
A class must not declare a member with a basename that is the same as the name of the class or of a type parameter of the class.
Your example fails the first item.

How to define optional parameters in F# modules?

I'm trying to re-write a tiny C# lib in F# and I've encountered an error. I'm trying to define optional parameters for a method in a module but the compiler says "Optional arguments are only permitted on type members".
I've checked why you can't use them in loose functions but when typing static member or member I get another error instead.
module Kingdom =
let Rule (?years : int) =
()
I thought this was going to wor kas it's how I understood you type it, after reading the Microsoft Docs article about it.
By using another way to define the "static class" you can add member to it. And then you can use optional parameters. The class will show up as a normal static class in C#.
[<AbstractClass; Sealed>]
type Kingdom private () =
static member Rule (?years : int) = ()

Get type of a module at compile time in F#

We know that in C# we can get type of a type at compile time using typeof(OutType) this lets us pass this to attributes later as it is constant expression.
I saw this question, but it doesn't really address the compile time usage.
So my question is: Is there a way to get System.Type of a given module at compile type within F# standard library?
F# disallows obtaining a module's type using its typeof operator by design, as they're not first-class concepts in the language.
From the spec, section 13.2:
F# modules are compiled to provide a corresponding compiled CLI type declaration and
System.Type object, although the System.Type object is not accessible by using the typeof
operator.
Modules compile to static classes however, so it is possible to obtain the type at runtime using reflection (and that's what happens in typeof<MyModule.Dummy>.DeclaringType example), and it's possible to obtain the type of a module defined in a referenced F# assembly using typeofoperator in C#.
For what you're trying to do, you'd best use a class instead of a module, because then you can get hold of the type without hassle:
type MyFactoryClass =
static member TestCases = [ 1; 2; 3 ]
...
[<Test; TestCaseSource(typeof<MyFactoryClass>, "TestCases">]
let test (arg: int) = ...
If you are OK to refer to a type inside that module (or create a dummy one if there are no types), you could do this:
module MyModule =
type Dummy = Dummy
let myModule = typeof<MyModule.Dummy>.DeclaringType

Is there an equivalent of C#'s using T = X.Y.Z import directive in F#?

In C# I can define an alias for a type by writing
using Foo = Full.Name.Space.Of.My.TypeWithAVeryLongName;
Within the code file I can from then on refer to my type via Foo instead of TypeWithAVeryLongName and there is no need to import Full.Name.Space.Of.My.
How do I have to change the open ... directive in F# to achieve something similar?
You can declare a type abbrevation:
type Foo = Full.Name.Space.Of.My.TypeWithAVeryLongName
Just some additinal info, if you just want an abbreviation for your type Taylor Wood's answer is the one.
If you want to abbreviate (or change) a module name, you can use:
module Short = MyVeryLong.Helpers.Container
where the namespace is defined as
module MyVeryLong.Helpers.Container in another place/file/dll. And you can refer to your type as Short.MyType.
but this will only work for a module nested in a namespace. To my knowledge you cannot abbreviate pure namespace names.

How to assign to base field?

I have a base class with a field called 'Root'. I am trying to assign a value to it by using the following code inside the do binding
base.Root <- somevar
I am getting the following error
error FS0419: 'base' values may only be used to make direct calls to the base implementations of overridden members
What am I missing? It is a field not property in the base class
Apparently, F# compiler does not allow mutating a field of the base class via base. reference in derived class constructor; and the error message prompts you of valid base. keyword usages.
Nevertheless, you may try a nasty hack, for example by upcasting constructed derived instance as in a snippet below :
type FormulaGrammar() as self =
inherit Grammar()
do
... stuff from your gist here......
(self :> Grammar).Root <- expr
Although after a brief peek into your C# prototype irony.aspx I'd say that similar part of constructor there uses not base Grammar, but derived type ExpressionGrammar for setting the Root field, which upon your code simply translates into self.Root <- expr.

Resources