Accessing let bound fields from static members - f#

Is there any way to access let bound fields from a static member? The following gives the indicated error:
type Foo(x) =
let x = x
static member test() =
let foo = Foo(System.DateTime.Now.Month)
printfn "%A" foo.x //the field, constructor or member 'x' is not defined
()
Whereas private explicit fields do allow access from static members:
type Bar =
val private x:int
new(x) = { x=x }
static member test() =
let Bar = Bar(System.DateTime.Now.Month)
printfn "%A" Bar.x
()
The documentation http://msdn.microsoft.com/en-us/library/dd469494.aspx states that "Explicit fields are not intended for routine use," yet accessing private instance fields from static members is certainly a routine scenario. Moreover, I don't believe you can set explicit fields within a primary constructor, which means if even one private instance field needs to be accessed from a static member, all of your fields must be moved over to explicit fields and you can no longer use a primary constructor -- it's all or nothing.
As real world example where you would actually want to access a private instance field from a static member, consider a big integer implementation: a BigInteger class would be immutable, so the internal representation of the big integer would kept as a private instance field (let's call it data). Now, suppose you felt an Add(other) instance method was inappropriate for an immutable data structure and you only wanted to implement a static Add(lhs,rhs) method: in this case, you would need to be able to access lhs.data and rhs.data.

I don't think you can do that... in fact, you can't access let-bound values from other instances either:
type Foo() =
let x = 3
member this.Test(f:Foo) =
f.x // same error
In general, if you need to access such a value from outside of the instance it belongs to, you should probably either create a private property to get the value or use a private field instead.
UPDATE
This is covered by section 8.6.2 of the spec. In particular:
Instance “let” bindings are lexically scoped (and thus implicitly private) to the object being defined.
Perhaps someone from the F# team will weigh in with a definitive answer as to why the language behaves this way. However, I can think of a couple of potential reasons:
let-bound values may not even be present as fields (e.g. again from the spec, a let binding will be represented by a local to the constructor "if the value is not a syntactic function, is not mutable and is not used in any function or member")
This seems consistent with the behavior of let bindings elsewhere in the language. See the examples of a roughly equivalent class and record definitions which I've included further down (because I can't seem to properly format code blocks within an ordered list...)
This provides a finer-grained level of encapsulation than is possible in many other languages - bindings which are local to the object being defined. Often, other instances will not need access to these bindings, in which case it's nice not to expose them.
If you want something which is accessible by other instances of your class (or from within static methods), there's an easy way to do that - create a private field or property, which has the benefit of explicitly expressing your intention that the value be accessible from outside of the instance that you are in.
As mentioned earlier, here are a roughly equivalent class definition and method to create a record:
type MyClass(i:int) =
let j = i * i
member this.IsSameAs(other:MyClass) =
false // can't access other.j here
type myRecord = { isSameAs : myRecord -> bool }
let makeMyRecord(i:int) =
let j = i * i
{ isSameAs = (fun r -> false) } //obviously, no way to access r.j here
Since constructors in F# are conceptually similar to any other function which returns an instance of a type (e.g. they can be called without using new), calling MyClass 5 is conceptually similar to calling makeMyRecord 5. In the latter case, we clearly don't expect that there is any way to access the local let binding for j from another instance of the record. Therefore, it's consistent that in the former case we also don't have any access to the binding.

yet, accessing let bound fields from
static members is certainly a routine
scenario
What do you mean here? What is the corresponding C# scenario (with an example)?
Note that this is legal:
type Foo() =
let x = 4
member this.Blah = x + 1
member private this.X = x
static member Test(foo:Foo) =
foo.X
That is, you can expose the let-bound value as a private member, which a static can read/use.

Related

How can I access static members in a generic context?

I need a workaround or idiomatic way to access the static members defined in some type from a generic context.
Example:
enum E { first, second, third }
// no direct syntax to constrain to enum types
class EnumKeyList<TEnum> {
List<Object> _values;
// unable to access static member
EnumKeyList() : _values = List.filled(TEnum.values.length, Object());
// unable to access instance member
Object operator [](TEnum entry) => _values[entry.index];
}
Usage:
final list = EnumKeyList<E>(); // E.values.length would provide implicit fixed-size list instantiation
list[E.first] = 5; // can use enumeration entries as keys
I want to avoid the overhead of Map (hashing and additional memory). The real use case must index into the list in tight loops.
Having a fixed set of named keys is a useful requirement, but the example EnumKeyList should work with any generic type argument that provides an enumeration like interface.
Using enumerations provides the shortest way to declare valid 0-indexed keys and the count of the amount of entries through an enumeration's static values member.
Swift enumerations and protocols allow for static members. C# has constraints for enumeration types. C++ generics dwarf everything. Is there a simple way to achieve this in Dart?
I realize that I can declare my own class instead of an enumeration, but then I lose the implicitly generated members (having to manually assign a value to each constant in the class (bad for maintenance)) and I still can't provide access to a static member from the generic context.
See here for examples of how unmaintainable this is:
abstract class Enum {
final int rawValue;
const Enum(this.rawValue) : assert(rawValue >= 0);
// don't bother with a static 'values' member
}
class E extends Enum {
const E(int rawValue) : super(rawValue);
static const first = E(0);
static const second = E(1);
static const third = E(1); // repeated values
static const List<E> values = <E>[first, second]; // missed one
}
You cannot access static members through type variables.
Dart static members are really just declared in the namespace of the corresponding class/mixin/extension declaration, they are not part of the type. Type variables hold types, not declarations.
There is no idiomatic workaround.
You have to figure out which operations you need your class to support, then you can introduce a strategy object representing the class, and pass that to the function instead of (or alongside) the type argument.
In this case, you probably want the EnumKeyList constructor to take the list of values as an argument, so:
EnumKeyList(List<T> values) : _values = List.unmodifiable(values);
The workaround, in general, is to pass the values you'd want to read from a static member directly to the function needing them, along with the type.
You can't access them using the type alone.
The "cannot access index" problem could be fixed by the language adding an interface to all enums, like abstract class Enum { int get index; } and make all enum classes implement that interface.
There is no easy way to allow access to the values knowing only the type.
It might be possible to do something magical in the compiler and platform libraries, but it won't extend to user-written enums like this, and no viable way to emulate it.

Create new instance of certain user type

I'm using tolua++ to automatically expose C++ types to Lua. It seems that when I expose some type, e.g.
struct TestComponent
{
float foo;
string bar;
}
What tolua does (at least this is what it seems like to me) is add a new metatable to the lua environment (in this case it would just be called TestComponent) with some regular metamethods such as __add, __lt, as well as __index, __newindex, etc. It also has some custom functions (called .set and .get) which seem to be used when you get or set certain members of the struct/class. The type of TestComponent here seems to be just "table".
However, what it seems to lack, for simple structure definitions like above, are functions/methods to create a new instance of the type TestComponent, e.g.
a = TestComponent:new()
The question, then, is, how do I create a new instance of this type and assign it to a variable? For example, to hand it to a function that expects an argument of type TestComponent.
It's been a few years since I used tolua++, but based on the docs it appears that if your struct had a constructor, then you could create the object with a = TestComponent() or a = TestComponent:new() (both should work, unless you have an older version of tolua++). Without a constructor in the C++ struct, the docs don't say, but based on what you state, it seems like the TestComponent becomes a regular table object with the given fields and associated values, in which case it does not make sense to have a constructor (the table is the object, you can't create multiple instances of it).
So if you can edit the C++ header of the struct to add a constructor to it, it'll probably work. If you can't do that, then you could define a constructor yourself (note: not tested):
function TestComponent:new()
local obj = {}
for k,v in pairs(self) do
obj[k] = v
setmetatable(obj, self)
return obj
end
You might have to filter the keys so you only get values (not functions, for example), or replace the loop with explicit assignments such as:
function TestComponent:new()
local obj = {}
obj.foo = self.foo
obj.bar = self.bar
setmetatable(obj, self)
return obj
end

F# Modify & Return

type Tag(Kids) =
member this.Kids = Kids
static member (-) (this: Tag, that: list<obj>) =
Tag(that::this.Kids)
The point of this code is to construct a new object based on an existing one, but modifying one (or more) fields on the object. Basically, it is a proxy for a thing.setX(...) mutator method, except using immutable data.
It looks incredibly ugly and verbose, and I'm sure there must be a better way of doing it while maintaining the immutability of the data, but I haven't figured out how. Is there some syntactically nice way of doing this?
EDIT: Just for clarity, I also have other classes in the hierarchy:
type HTMLTag(s, Classes, Kids, Styles) =
inherit Tag(Kids)
member this.NominalTag = s
member this.Classes = Classes
member this.Styles: list<String * String> = Styles
static member (-) (this: HTMLTag, that: list<obj>) =
HTMLTag(this.NominalTag, this.Classes, that::this.Kids, this.Styles)
Apart from it being very verbose, the - function's "copy with modification" thing is completely non-generic: even though I am doing the same thing each time (copy w/ modification to same variable) I have to rewrite the whole thing all over again, which isn't very nice.
One thing I find very annoying is that this would be very simple with mutation:
static member (-) (this: Tag, that: list<obj>) =
this.Kids = that :: this.Kids
this
But I'm trying to keep everything immutable as far as possible
Copy and update record expressions[MSDN] are meant to handle this exact case. If you can use a record type instead you can do
type Tag =
{ NominalTag : obj
Classes : obj
Kids : list<obj>
Styles : list<String * String> }
static member (-) (this: Tag, that: list<obj>) =
{ this with Kids = this.Kids # that }
The compiled forms of this code and yours are virtually identical.
Incidentally, it's odd that the (-) operator is being used to append...but I presume this is a contrived case.
UPDATE
Now that you've updated your question I'm confused about what you want to do. If you want to return a new object I don't see how mutation helps you.
A more functional approach (vs inheritance) is to separate your data and behaviors, the data being records and the behaviors functions grouped within a module. If you want behavior to be shared across types, use interfaces. Records can implement interfaces.

Cyclic function/type dependency in F#

I have a question about the best way to go about the following
I Have a class B, I have a combinator on B,
let foo : B -> int.
I want the class B to have the combinator encapsulated as a method, so I add it with a type extension.
I then later on realize that foo is quite expensive and want to cache it's result with lazy evaluation
So I add a huge clutch to the system by passing the combinator as a function to the constructor and then initializing a field with foo = lazy(foo self) in the constructor.
i.e.
type foo =
class
val x : int Lazy
new (comb) as self = {x=lazy(comb self);}
end
let something (x:foo) = 1
type foo with
new() = foo(something)
this obviously feels wrong
the two options I see for fixing this are 1, make an interface and have foo inherit that interface, 2, make everything a static method and then make combinators out of those static methods(sort of the opposite of attaching them to classes...)
Neither of these are hugely appealing and I was wondering if I missed option 3
Oh, and I haven't been able to get let rec and to work quite right with this, nor would i really want to as "something" in the above statement depends on a function that depends on a function that depends on a function(3 deep).
any advice would be appreciated
I don't think there is anything wrong with your current design. The key point is that if you define the type Foo as well as the extension to the type in a same file (and the same module), then F# will combine the two parts of the definition into a single .NET type. So, the fact that it is defined in two separate parts is just an implementation detail.
If you don't want to expose the constructor that takes the combinator, you can mark it as private. Together with a few additional changes (i.e. use implicit constructor syntax), the snippet would look like this:
type Foo private (comb) as self =
let x : Lazy<int> = lazy comb self
let something (x:Foo) = 1
type Foo with
new() = Foo(something)
If you want to keep something as a separate function, then this is a fine solution. Many numeric types in the F# PowerPack follow this pattern (see for example definition of complex numbers)
I don't quite grok what you're after, but I think this may help:
type foo(comb) as self =
let x = lazy(comb self)
static member something (x:foo) = 1
new() = foo(foo.something)
A type can be recursive with its own static member, so this is a simpler way to write your code.

Unknown need for type annotation or cast

I know I must be missing something really obvious here. B.GetInstance().Call() generates the error: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
I'm using v1.9.9.9.
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() = new B()
member x.Call() = ()
I just discovered that this works: (B.GetInstance() :> B).Call()
Any idea why the cast is necessary?
Frequently when you've got a recursive set of methods whose types to infer, F# needs help. A more pleasant alternative would be to annotate the definition of B.GetInstance:
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() : B = new B()
member x.Call() = ()
I believe that the reason you run into this problem is that F# tries to solve all inferred types on all methods in A and B simultaneously (because they are defined as mutually recursive types), and this leads to problems, but perhaps someone from the F# team will weigh in.
The quick summary is that in a recursive group (e.g. members in one type, or members of recursive types like we have here) F# reads the declarations in left-to-right top-to-bottom order, followed by the definitions in left-to-right top-to-bottom order. So in this instance when it reaches the definition of A.Call, it has not yet read the definition of B.GetInstance and therefore does not (yet!) know that the return type of GetInstance will be B.
Keith's answer nails it for this situation, you can provide a type annotation to specify the return type of GetInstance in its declaration.
See
Forcing F# type inference on generics and interfaces to stay loose
for a deep discussion of what's going on here.
Note also that in your original attempt, you don't need to "cast" (the potentially dynamic operation, using :>), instead you can just "annotate" (statically declare a type, using :) to get it to compile. But makes more sense to put the type annotation in the method declaration for GetInstance (generally, prefer addition annotations to method signatures instead of arbitrary places inside bodies).

Resources