I have made a member function in a class. Afterwards I want to make a member value that is set to the result of this member function.
type MyType() =
member this.drawFilledPlanet(xCoord:int, yCoord:int, pWidth:int, pHeight:int, color) =
let brush = new System.Drawing.SolidBrush(color)
this.window.Paint.Add(fun e ->
e.Graphics.FillEllipse(brush, xCoord, yCoord, pWidth, pHeight))
member val theSun = drawFilledPlanet(350,350,100,100, this.yellow)
I am getting the error that drawFilledPlanet is not defined.
Can someone tell me what is up?
Because drawFilledPlanet is a member function, it needs a class instance on which it's to be called. If you're calling it from another member function, you would use that member's definition to name the current instance:
member this.f() = this.drawFilledPlanet ...
In your case, however, since you're defining a member val, you don't have that opportunity. In this situation, you can name the current instance at the very top of the class declaration:
type MyType() as this =
...
member val theSun = this.drawFilledPlanet ...
One thing I'd like to point out is that this definition may not have the effect that you expect. If you define theSun this way, the drawFilledPlanet method will only get executed once at class initialization, not every time theSun is accessed. Did you intend that? If no, then you need to change the definition. If yes, then why do you need this definition at all?
Related
This is probably asked several times but I just can't find an example.
My goal is to define an event handler for an event and the handler should be a member of the class. In other words I don't want to use function since I need to access instance variables and members
The latest variation I've tried:
namespace A
type ValueList<'TValueItem when 'TValueItem :> IValueItem>() =
inherit System.Collections.ObjectModel.ObservableCollection<'TValueItem>()
// This is causing error: The value or constructor 'ValueList_CollectionChanged' is not defined
let collectionChangedHandler = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ValueList_CollectionChanged)
// Constructor code
do base.CollectionChanged.AddHandler(collectionChangedHandler)
// Handles collection changed events for data items
member this.ValueList_CollectionChanged(sender : obj, e : System.Collections.Specialized.NotifyCollectionChangedEventArgs) =
// The code I want to run goes here
...
Or is this maybe a completely wrong approach?
Looks like you're looking for the self-identifier syntax:
type ValueList<'TValueItem when 'TValueItem :> IValueItem>() as this =
The as this (or any other identifier in place of this) allows to refer to the instance being constructed from the constructor.
You could then change your other lines to use the identifier:
let collectionChangedHandler = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(this.ValueList_CollectionChanged)
do this.CollectionChanged.AddHandler(collectionChangedHandler)
For this to be valid as-is, the ValueList_CollectionChanged method also needs to be in curried form:
member this.ValueList_CollectionChanged (sender : obj) (e : System.Collections.Specialized.NotifyCollectionChangedEventArgs) =
As an alternative to using curried arguments, you can use a lambda to transform the arguments where the handler is instantiated, e.g. .NotifyCollectionChangedEventHandler(fun sender e -> this.(...).
Just curious why F# has:
member val Foo = ... with get, set
While omitting the self identifier (e.g. this.).
This is still an instance property. Maybe I am the only one confused when using it. But just bothered me enough to query whoever knows how the language was defined.
With this syntax, the property is almost totally auto-implemented -- all you provide is the initialization code, which essentially runs as part of the constructor.
One of the best-practice guard rails F# puts in place is that it does not let you access instance members before the instance is fully initialized. (wow, crazy idea, right?).
So you would have no use for a self-identifier in auto-props, anyways, since the only code you get to write is init code that can't touch instance members.
Per the MSDN docs (emphasis mine):
Automatically implemented properties are part of the initialization of
a type, so they must be included before any other member definitions,
just like let bindings and do bindings in a type definition. Note that
the expression that initializes an automatically implemented property
is only evaluated upon initialization, and not every time the property
is accessed. This behavior is in contrast to the behavior of an
explicitly implemented property. What this effectively means is that
the code to initialize these properties is added to the constructor of
a class.
Btw, if you try to be a smartass and use the class-level self-identifier to get around this, you'll still blow up at runtime:
type A() as this =
member val X =
this.Y + 10
with get, set
member this.Y = 42
let a = A()
System.InvalidOperationException: The initialization of an object or value resulted in an object or value being accessed recursively before it was fully initialized.
at Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions.FailInit()
at FSI_0013.A.get_Y()
at FSI_0013.A..ctor()
at <StartupCode$FSI_0014>.$FSI_0014.main#()
Edit: Worth noting that in upcoming C# 6, they also now allow auto-props with initializers (more F# features stolen for C#, shocker :-P), and there is a similar restriction that you can't use the self-identifier:
class A
{
// error CS0027: Keyword 'this' is not available in the current context
public int X { get; set; } = this.Y + 10;
public int Y = 42;
public A() { }
}
I want to implement IEnumerable<KeyValuePair<DateTime, 'T>> in my own class and add math operators to that class so that the operators could work like inline function on any numeric types of 'T - automatically add constraints.
I just cannot make the following piece of code work. It doesn't work neither with nor without 'inline' keyword at the member declaration.
Also, if I define a function
let inline add l r = l + r
before the type and use it instead of addition l.Value + r.Value, it also doesn't work.
Could someone please show me what I am doing wrong?
Probably the whole approach is wrong and there is a way to achieve the same goal the other way?
namespace Test
open System
open System.Linq
open System.Collections.Generic
[<SerializableAttribute>]
type TimeSeries<'T>(dictionary : IDictionary<DateTime, 'T>) =
let internalList = new SortedList<DateTime, 'T>(dictionary)
interface IEnumerable<KeyValuePair<DateTime, 'T>> with
member this.GetEnumerator() = internalList.GetEnumerator()
member this.GetEnumerator() : Collections.IEnumerator
= internalList.GetEnumerator() :> Collections.IEnumerator
member private this.sl = internalList
static member inline (+) (left : TimeSeries<'T>, right : TimeSeries<'T>) =
let res =
query {
for l in left do
join r in right on
(l.Key = r.Key)
select (l.Key, l.Value + r.Value)
}
new TimeSeries<'T>(res |> dict)
Your approach seems correct to me.
The reason why your code doesn't compile is because F# type inference is inferring a static constraint (compile-time) for the type variable 'T which is the same used for the type definition.
A generic parameter of a type definition can't be statically resolved (no "hat" types) but nothing stops you from defining a function or a member which uses these compile-time constraints.
Just change your type variable 'T to 'U in the static member (+) definition and it will be fine.
Still you'll be allowed to create a TimeSeries instance of a type which does not support (+) (ie: TimeSeries<obj>) but you will not be able to use (+) for those instances, anyway if you do it you'll get a nice error message at compile-time.
I am trying to create two types where one is able to remove itself from the other such as in this example.
type employee (workplace : Job) =
member this.Fire () = workplace.Employees.Remove(this) |> ignore
and Job () =
let employees = new ResizeArray<employee>()
member this.Employees = employees
But this gets me the compile error of "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 not sure what I am doing wrong here. Any help would be appreciated
You can solve the problem even without reordering the declarations - when the F# compiler type-checks the Employee declaration, it doesn't yet know what is the type of workplace.Employees (because the type hasn't been declared yet), so it doesn't know where does the Remove method come from. You can correct that by adding type annotation that specifies that Employees is ResizeArray<Employee>:
type Employee (workplace : Job) =
member this.Fire () =
let emps : ResizeArray<Employee> = workplace.Employees
emps.Remove(this) |> ignore
and Job () =
let employees = new ResizeArray<Employee>()
member this.Employees = employees
However, this example isn't very functional - if you're going to use mutable state (such as ResizeArray), then the state should be hidden as private state of the type (so Jobs could have a Remove method).
In general, declaring recursive type declarations is a bit less comfortable in F# - however, you shouldn't need them that often. Quite frequently, you can use more generic types (i.e. Job may not need to know abou the Employee type).
Try this..
type Job () =
let employees = new ResizeArray<employee>()
member this.Employees = employees
and employee (workplace : Job) =
member this.Fire () = workplace.Employees.Remove(this) |> ignore
I've been struggling to get this to compile for about an hour. It must be something stupid. Can you spot it?
in my lib project:
namespace TravelerStuff
open System
type Traveler =
abstract GetData : unit -> unit
type public DeltaTraveler() =
interface Traveler with
member v.GetData () =
printf "hello"
and in my console test app:
[<EntryPoint>] let main _ =
let traveler = new TravelerStuff.DeltaTraveler()
traveler.GetData // this line won't compile: (The field, constructor or member 'GetData' is not defined)
As gradbot says, F# doesn't currently implicitly convert values to interfaces when searching for members. Also, F# only uses explicit interface implementation (as known from C#) and not implicit implementation where members are not only compiled as implementation of an interface, but also as ordinary (directly visible) members of the type.
Aside from casting, you can duplicate the member in the type definition:
type DeltaTraveler() =
member v.GetData () = printf "hello"
interface Traveler with
member v.GetData () = v.GetData()
Also, if you just want to implement an interface, but don't need to add any members, you can use F# object expressions (which are more lightweight):
let deltaTraveler() =
{ new Traveler with
member v.GetData () = printf "hello" }
// The function directly returns value of type 'Traveler'
let t = deltaTraveler()
t.GetData()
You need to upcast. F# currently won't do it for you in this situation.
(traveler :> TravelerStuff.Traveler).GetData()
// open the namespace to reduce typing.
open TravelerStuff
(traveler :> Traveler).GetData()
Snip from F# docs.
In many object-oriented languages,
upcasting is implicit; in F#, the
rules are slightly different.
Upcasting is applied automatically
when you pass arguments to methods on
an object type. However, for let-bound
functions in a module, upcasting is
not automatic, unless the parameter
type is declared as a flexible type.
For more information, see Flexible Types (F#).