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.
Related
I think I understand what's happening here, but I'd really appreciate someone throwing some light on why it's happening.
Basically (and I'm coding on the fly here, to give the simplest possible illustration) I have a class S which, among other things, maintains a symbol table relating names to objects of the class. So, inside the class I define:
static member (names:Map<string,S> ref) = ref Map.empty
... and then later on, also in S, I define:
member this.addSymbol (table: Map<string,S> ref) (name:string)
table := (!table).Add(name, this)
this
I call this from elsewhere, thus:
ignore (s.addSymbol S.names "newname")
...
Inside S.addSymbol I can see the new key/value being added to table, but S.names doesn't get updated. If, instead, I call addSymbol like this:
ignore (
let tmp = S.names
s.addSymbol tmp "newName"
)
then I can see tmp being updated with the new key/value pair, but S.names still doesn't get updated.
Here's what I think I know: there's nothing wrong with the ref mechanism - that's updating the referent correctly both inside and outside the function. But there seems to be something odd about the static member - it's like, rather than just handing me the same static ref 'a each time, it's copying the 'a and then creating a new ref for that.
Have I got this right? If so, why is it doing it? And what can I do to make it behave more sensibly?
Thanks in advance.
The static member names is a property, not a static value. It is, internally, a function that creates a new map every time it is called.
If the value has to be in the class, use static let to define it inside the class. That way, the reference cell is only created once.
type S () =
static let names = ref Map.empty : Map<string, S> ref
static member Names = names
S.Names := ["Don", S()] |> Map.ofList
S.Names // gives map with one element
Oftentimes, the class doesn't expose the reference cell itself, but rather members to read, add, or remove names. Then, Names would return !names -- or names would be a plain mutable instead of a reference cell -- and other methods like AddName would alter the value. If there is no need for such encapsulation, see kvb's comment for how to shorten this example to only one member. (Thanks for the hint!)
Alternative: Normally, this is a case in which F# modules are used. Just define
let names = ref Map.empty : Map<string, S> ref
or
let mutable names = Map.empty : Map<string, S>
in a module, with additional access restrictions or encapsulation as required.
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.
Is it possible to implement friend function and friend class (as in c++) in F#?
Update:
Since there is no friend function/class in f#, and friend is not even a reserved keyword for future expansion, I'm wondering is there any problems with the friend mechanism in F# that make the developers to decide not to implement it?
(such as in "protected" access modifier).
Suggestion 1: Brian, signature file -
I don't think that this thing work properly. If you have a closure (e.g. lambda expression in A, which is a different object than the instance of A) that evaluate B.X , it's won't work
Suggestion 2: Massif (+Mitya0), InternalsVisibleTo -
It's not clear to me, Are you writing this in the second class or it expose the class to the entire assembly?
Note that you can use signature files to mimic friend.
If you want A to be a friend of B, so A can access internals of B that others cannot see, you can do e.g.
// File1.fs
type B() =
let x = 42 // private field
member this.X = x // public getter
type A() =
member this.PeekInto(b : B) =
b.X
but also have
// File1.fsi
type B =
new : unit -> B
// do not expose X in the signature
type A =
new : unit -> A
PeekInto : B -> int
and now A's implementation can see B.X but the sequel of the program cannot see B.X.
Signature files are pretty awesome for creating arbitrary encapsulation boundaries.
As mitya has pointed out. Just use the InternalsVisibleTo attribute on the class you want to see the protected members of, or on the entire assembly. (I do this all the time for unit testing purposes).
[<assembly:System.Runtime.CompilerServices.InternalsVisibleTo("UnitTestModule")>]
Works a treat.
The concept of friends as it exists in C++ doesn't exactly translate to F#, but you can use the internal accessibility modifier to allow access to all classes in the same .NET assembly. This is probably what you are looking for.
From what I see of documentation, there is a friend notion in C#, but the same documentation suggests F# doesn't have this ability.
I've recently been trying to learn the Object-Oriented aspects of F#, and have become curious about how to restrict access to types/modules in the language.
More specifically, I want to know the difference between writing this:
Example.fsi
module Stack =
val foo : string
Example.fs
module Stack =
let foo = "foo"
let bar = "bar"
and alternatively this:
module Stack =
let foo = "foo"
let private bar = "bar"
Do they not accomplish exactly the same thing in the end? Coming from a C# background, I'm much inclined just to use the access modifiers over signature (FSI) files. They seem to be more versatile (can apply to modules/types in namespaces, for example), whereas I don't any situation in which signature files offer something that access modifiers don't.
They accomplish almost the same thing. (Note that you can use an .fsi file for types in namespaces too, was unsure what your comment about that meant.)
A signature file has a couple advantages:
You can make entities public for the duration of the file, but then private to the subsequent files of the project.
You can have just your short summary in the signature file, so the public interface is easy to read without having to scan tons of code.
The first bullet is not to be trifled with - within-assembly encapsulation like this is actually a pretty huge feature for very large projects. Being able to define a few types which are public to one another within File1.fs, but then only have a subset of those types/methods be public to the rest (File2.fs, File3.fs, etc.) is quite useful (a little bit like 'friend' in C++).
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).