Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive objects in F#?

Tags:

recursion

f#

This snippet of F# code

    let rec reformat = new EventHandler(fun _ _ ->
        b.TextChanged.RemoveHandler reformat
        b |> ScrollParser.rewrite_contents_of_rtb
        b.TextChanged.AddHandler reformat
        )
    b.TextChanged.AddHandler reformat

results in the following warning:

traynote.fs(62,41): warning FS0040: This and other recursive references to the object(s) being defined will be checked for initialization-soundness at runtime through the use of a delayed reference. This is because you are defining one or more recursive objects, rather than recursive functions. This warning may be suppressed by using '#nowarn "40"' or '--nowarn:40'.

Is there a way in which the code can be rewritten to avoid this warning? Or is there no kosher way of having recursive objects in F#?

like image 688
Muhammad Alkarouri Avatar asked Dec 26 '11 14:12

Muhammad Alkarouri


People also ask

What is a recursive object?

Objects can have other objects as attribute values. When an object of some class has an attribute value of that same class, it is a recursive object.

What are the 3 parts of a recursive function?

A recursive case has three components: divide the problem into one or more simpler or smaller parts of the problem, call the function (recursively) on each part, and. combine the solutions of the parts into a solution for the problem.

What is a recursive function example?

Simple examples of a recursive function include the factorial, where an integer is multiplied by itself while being incrementally lowered. Many other self-referencing functions in a loop could be called recursive functions, for example, where n = n + 1 given an operating range.

What is the recursive part in recursive factorial function?

The recursive step is the set of all cases where a recursive call, or a function call to itself, is made. The base case is , which is trivial to compute: . In the recursive step, n is multiplied by the result of a recursive call to the factorial of . TRY IT!


1 Answers

Your code is a perfectly fine way to construct a recursive object. The compiler emits a warning, because it cannot guarantee that the reference won't be accessed before it is initialized (which would cause a runtime error). However, if you know that EventHandler does not call the provided lambda function during the construction (it does not), then you can safely ignore the warning.

To give an example where the warning actually shows a problem, you can try the following code:

type Evil(f) =
  let n = f() 
  member x.N = n + 1

let rec e = Evil(fun () -> 
  printfn "%d" (e:Evil).N; 1)

The Evil class takes a function in a constructor and calls it during the construction. As a result, the recursive reference in the lambda function tries to access e before it is set to a value (and you'll get a runtime error). However, especially when working with event handlers, this is not an issue (and you get the warnning when you're using recursive objects correctly).

If you want to get rid of the warning, you can rewrite the code using explicit ref values and using null, but then you'll be in the same danger of a runtime error, just without the warning and with uglier code:

let foo (evt:IEvent<_, _>) = 
  let eh = ref null
  eh := new EventHandler(fun _ _ -> 
    evt.RemoveHandler(!eh) )
  evt.AddHandler(!eh)
like image 87
Tomas Petricek Avatar answered Sep 19 '22 18:09

Tomas Petricek