Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cyclic dependency of modules

Tags:

f#

I want to write a parser in F# and because of reasons I have to use Antlr. This means I have to define a Visitor class for every AST node I want to parse. Now I have the problem that there are some rules with cyclic dependencies like:

boolExpr : boolTerm 'or' boolTerm ;
boolTerm : boolAtom 'and' boolAtom ;
boolAtom : '(' boolExpr ')' 
         | ... ;

which means I need 3 visitor classes that have the same cyclic dependency and I want to have each of them in their own file

//BoolExprVisitor.fs
let boolExprVisitor = { new BaseVisitor<AST.BoolExpr>() with
    override __.VisitBoolExpr(context: BoolExprContext) =
        context.boolTerm() |> mapAccept boolTermVisitor |> AST.BoolExpr
}

//BoolTermVisitor.fs
let boolTermVisitor = { new BaseVisitor<AST.BoolTerm>() with
    override __.VisitBoolTerm(context: BoolTermContext) =
        context.boolAtom() |> mapAccept boolAtomVisitor |> AST.BoolTerm
}

//BoolAtomVisitor.fs
let boolAtomVisitor = { new BaseVisitor<AST.BoolAtom>() with
    override __.VisitBoolAtom(context: BoolAtomContext) =
        context.boolExpr() |> accept boolExprVisitor |> AST.BoolAtom
}

But F# doesn't like these cyclic dependencies. How can I make F# accept them or restructure my visitors to not need cyclid dependencies?

like image 328
danielspaniol Avatar asked Jun 08 '18 07:06

danielspaniol


People also ask

How do you fix cyclic dependency?

There are a couple of options to get rid of circular dependencies. For a longer chain, A -> B -> C -> D -> A , if one of the references is removed (for instance, the D -> A reference), the cyclic reference pattern is broken, as well. For simpler patterns, such as A -> B -> A , refactoring may be necessary.

What is cyclic dependency in Python?

When two or more modules rely on each other, this is referred to as a circular dependency. This is due to the fact that each module is defined in terms of the others. Python cyclic imports. Let's take these two python files as an example. # file1.

What is cyclic dependency in Java?

A circular or cyclic dependency is a situation where two or more independent modules or components rely on each other to function properly. This is referred to as mutual recursion. Circular dependency generally occurs in a modular framework while defining a dependency between modules or components.

What is a dependency cycle?

A dependency cycle is a relationship between two or more domains that lead to a situation where a slave domain depends on itself, or a master domain depends on one of its slave domains. The Logical Domains Manager determines whether a dependency cycle exists before adding a dependency.


1 Answers

For anyone coming across this problem in the future:
As rmunn said, the fact that I wanted the classes in different files was simply not good design. Also I did not need different AST nodes for BoolTerm, BoolAtom and BoolExpr as they could all be described as the same node BoolExpr.

My solution was to merge all of the boolean expression visitors into the same class (and merge all files for expression visitors into a single file):

//AST.fs
type BoolExpr = 
    | BoolConjunctionExpr of BoolOp * BoolExpr list
    | ...

//ExpressionVisitors.fs
let boolExprVisitor = { new BaseVisitor<AST.BoolExpr>() with
    override this.VisitBoolExpr(context: BoolExprContext) =
        context.boolTerm() |> mapAccept this |> AST.BoolConjunctionExpr AST.Or

    override this.VisitBoolTerm(context: BoolTermContext) =
        context.boolAtom() |> mapAccept this |> AST.BoolConjunctionExpr AST.And

    override this.VisitBoolAtom(context: BoolAtomContext) =
        context.boolExpr() |> accept this
}
like image 161
danielspaniol Avatar answered Oct 12 '22 19:10

danielspaniol