Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does F# support interdependent classes in separate files?

I'm working on IronJS, and one of our source files is getting very long.

Right now, I'm trying to get .NET interop working. I'm adding the TryBinaryOperation method to the Undefined so that C# can use the JavaScript semantics of the Undefined value.

However, this introduces a dependency on the Operators type, which causes a circular dependency.

Runtime.fs:

type BoxedValue() =
    struct
        // Contains IsUndefined and get_Undefined, referencing the Undefined class, below.

...

and type Undefined() =
    inherit DynamicObject()
    ...
    override x.TryBinaryOperation(binder:BinaryOperationBinder, arg:obj, result:obj byref) : bool =
        // Here, we are referencing BoxedValue, above.
        result <- Operators.add(Und, BoxedValue.Box(arg))
        true

...

Operators.fs:

type Operators =
    ...
    // Here, we are referencing BoxedValue.
    static member add(BoxedValue l, BoxedValue r)
        ...

So, we have this set of dependencies:
BoxedValue->Undefined, Undefined->BoxedValue, Undefined->Operators, Operators->BoxedValue

Ideally, we would like to split each of these into its own file.

Is it possible in F# to have cross-file circular dependencies?

like image 996
John Gietzen Avatar asked Jul 03 '11 21:07

John Gietzen


People also ask

Does f mean derivative?

Derivative as a functionLet f be a function that has a derivative at every point in its domain. We can then define a function that maps every point x to the value of the derivative of f at x. This function is written f′ and is called the derivative function or the derivative of f.

What is the f in calculus?

The Notation of Differentiation One type of notation for derivatives is sometimes called prime notation. The function f ´( x ), which would be read `` f -prime of x '', means the derivative of f ( x ) with respect to x . If we say y = f ( x ), then y ´ (read `` y -prime'') = f ´( x ).

What does f say about f and f?

f, f′ and f″ Since (f′)′=f″, when f′ is increasing, f″ is positive. Similarly, when the slopes of tangent lines are decreasing, i.e. when f′ is decreasing, the function is concave down, as you can see in the second two graphs below. Since (f′)′=f″, when f′ is decreasing, f″ is negative.


1 Answers

There is no direct way to write circular dependencies between types defined in separate files (in the current version of F#). In general, the way to solve the problem is to break one of the dependencies and allow some form of parameterization. Then you can fill the hole to build the circular reference later.

In your example, you can probably reasonably easily parameterize the Undefined type to take the reference to Operators as a parameter. If you need more functions, then you can use an interface. For just a single function (like Operators.add) you can write something like this:

and type Undefined() =
    inherit DynamicObject()
    ...
    // To be specified by code defined later 
    // (this can either be a function or an interface implementation)
    static let mutable addition = (fun x y -> failwith "not initialized")
    static member SetAddition(f) = addition <- f

    override x.TryBinaryOperation
            (binder:BinaryOperationBinder, arg:obj, result:obj byref) : bool =
        // Here, we are referencing BoxedValue, above.
        result <- addition(Und, BoxedValue.Box(arg))
        true

The code in Operators.fs would provide the implementation:

type Operators =
    ...
    // Static constructor of the `Operators` type
    static do Undefined.SetAddition(Operators.add)
    ....

    // Here, we are referencing BoxedValue.
    static member add(BoxedValue l, BoxedValue r)

The only tricky thing is that you need to make sure that the static constructor of Operators will get called before the Undefined type is used for the first time. This depends on your specific case, but there is usually some way to do that. (There is probably some main type that can run the initialization)

like image 112
Tomas Petricek Avatar answered Sep 18 '22 22:09

Tomas Petricek