2
votes

I can use functions of modules and static member functions with the pipeline operator. Can I use it with non-static member functions?

My class:

type MyClass =
    class
        new() = {}

        member this.isZero(number: int): bool =
            number = 0

        static member returnInt(): int =
            33
    end

Using the static member:

MyClass.returnInt() |> Console.WriteLine // prints 33

Using the non-static member:

let foo = new MyClass()
foo.isZero(2) |> Console.WriteLine // prints false

I want use the non-static function from my object. Invalid syntax:

let foo = new MyClass()
foo |> member MyClass.isZero(2) |> Console.WriteLine

I'm trying use the clear syntax of F#.

1
What are you trying to achieve that the code under "Using the non-static member" doesn't do? member is never used anywhere else than in the actual member declarations. - TeaDrivenDev
I think the OP is trying to do this: fslang.uservoice.com/forums/245727-f-language/suggestions/… And no, it's not possible. In your example, what's wrong with doing foo.isZero(2)? - Fyodor Soikin

1 Answers

3
votes

If you already have an identifier for the instance, like foo in the question, foo.isZero(2) |> ... is short and readable. Inside a longer pipeline, use a lambda expression:

funcThatReturnsMyClass(...) |> fun m -> m.isZero(2) |> Console.WriteLine

Note precedence though; you may want to add parentheses around the lambda when things get complicated, i.e. |> (fun m -> ...) |>.

If this case turns up a lot, adding some curried functions can help. This works well with the convention that instance members start with a capital letter, while static members or let-bound functions start with a lowercase letter. This way, if you need pipelines a lot but also want to support dot-notation, you can define both kinds of syntax:

type MyClass2 (magicInt : int) =
    member __.IsMagic i = i = magicInt
    static member inline isMagic i (instance : MyClass2) = instance.IsMagic i

Now, you can use dot-notation on instances, but also pipeline: |> MyClass2.isMagic 2 |> ...

The implementation of isMagic might look excessive, but the point is to forward to the other implementation without extra cost. This is usually better than copying the implementation, even if the implementation is short, since it creates no extra variant that can get out of sync, might need extra testing, etc.