Repository: dominikbraun/graph
Pull request #53 (2022-10-14 20:16:21)

Rename `PermitCycles` to `PreventCycles`
Probably my most embarrassing PR so far.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8ef3ccc..b042128 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
 ### Changed
 * Changed `AddVertex` to accept functional options.
+* Renamed `PermitCycles` to `PreventCycles`. This seems to be the price to pay if English isn't a library author's native language.
 
 ### Fixed
 * Fixed the behavior of `ShortestPath` when the target vertex is not reachable from one of the visited vertices.
diff --git a/README.md b/README.md
index 18ab57f..14e4bf2 100644
--- a/README.md
+++ b/README.md
@@ -170,7 +170,7 @@ fmt.Println(path)
 ![topological sort](img/topological-sort.svg)
 
 ```go
-g := graph.New(graph.IntHash, graph.Directed(), graph.PermitCycles())
+g := graph.New(graph.IntHash, graph.Directed(), graph.PreventCycles())
 
 // Add vertices and edges ...
 
@@ -188,7 +188,7 @@ fmt.Println(order)
 ![transitive reduction](img/transitive-reduction.svg)
 
 ```go
-g := graph.New(graph.StringHash, graph.Directed(), graph.PermitCycles())
+g := graph.New(graph.StringHash, graph.Directed(), graph.PreventCycles())
 
 // Add vertices and edges ...
 
@@ -200,7 +200,7 @@ _ := graph.TransitiveReduction(g)
 ![cycle checks](img/cycles.svg)
 
 ```go
-g := graph.New(graph.IntHash, graph.PermitCycles())
+g := graph.New(graph.IntHash, graph.PreventCycles())
 
 g.AddVertex(1)
 g.AddVertex(2)
diff --git a/dag.go b/dag.go
index 3e6c012..a33be7e 100644
--- a/dag.go
+++ b/dag.go
@@ -13,7 +13,7 @@ import (
 // recursively and uses Kahn's algorithm.
 func TopologicalSort[K comparable, T any](g Graph[K, T]) ([]K, error) {
 	if !isDAG(g) {
-		return nil, errors.New("topological sort can only be performed on DAGs created with the PermitCycles option")
+		return nil, errors.New("topological sort can only be performed on DAGs created with the PreventCycles option")
 	}
 
 	predecessorMap, err := g.PredecessorMap()
@@ -62,7 +62,7 @@ func TopologicalSort[K comparable, T any](g Graph[K, T]) ([]K, error) {
 // With a time complexity of O(V(V+E)), TransitiveReduction is a very costly operation.
 func TransitiveReduction[K comparable, T any](g Graph[K, T]) error {
 	if !isDAG(g) {
-		return errors.New("topological sort can only be performed on DAGs created with the PermitCycles option")
+		return errors.New("topological sort can only be performed on DAGs created with the PreventCycles option")
 	}
 
 	adjacencyMap, err := g.AdjacencyMap()
@@ -97,5 +97,5 @@ func TransitiveReduction[K comparable, T any](g Graph[K, T]) error {
 }
 
 func isDAG[K comparable, T any](g Graph[K, T]) bool {
-	return g.Traits().IsDirected && g.Traits().PermitCycles
+	return g.Traits().IsDirected && g.Traits().PreventCycles
 }
diff --git a/directed.go b/directed.go
index c737274..0bd5b6d 100644
--- a/directed.go
+++ b/directed.go
@@ -84,8 +84,8 @@ func (d *directed[K, T]) AddEdge(sourceHash, targetHash K, options ...func(*Edge
 		return fmt.Errorf("an edge between vertices %v and %v already exists", sourceHash, targetHash)
 	}
 
-	// If the user opted in to permitting cycles, run a cycle check.
-	if d.traits.PermitCycles {
+	// If the user opted in to preventing cycles, run a cycle check.
+	if d.traits.PreventCycles {
 		createsCycle, err := CreatesCycle[K, T](d, sourceHash, targetHash)
 		if err != nil {
 			return fmt.Errorf("failed to check for cycles: %w", err)
diff --git a/traits.go b/traits.go
index 72e6b61..11b7357 100644
--- a/traits.go
+++ b/traits.go
@@ -8,11 +8,11 @@ package graph
 //
 // This will set the IsDirected field to true.
 type Traits struct {
-	IsDirected   bool
-	IsAcyclic    bool
-	IsWeighted   bool
-	IsRooted     bool
-	PermitCycles bool
+	IsDirected    bool
+	IsAcyclic     bool
+	IsWeighted    bool
+	IsRooted      bool
+	PreventCycles bool
 }
 
 // Directed creates a directed graph. This has implications on graph traversal and the order of
@@ -24,7 +24,7 @@ func Directed() func(*Traits) {
 }
 
 // Acyclic creates an acyclic graph. Note that creating edges that form a cycle will still be
-// possible. To prevent this explicitly, use PermitCycles.
+// possible. To prevent this explicitly, use PreventCycles.
 func Acyclic() func(*Traits) {
 	return func(t *Traits) {
 		t.IsAcyclic = true
@@ -53,11 +53,11 @@ func Tree() func(*Traits) {
 	}
 }
 
-// PermitCycles creates an acyclic graph that permits and proactively prevents the creation of
+// PreventCycles creates an acyclic graph that prevents and proactively prevents the creation of
 // cycles. These cycle checks affect the performance and complexity of operations such as AddEdge.
-func PermitCycles() func(*Traits) {
+func PreventCycles() func(*Traits) {
 	return func(t *Traits) {
 		Acyclic()(t)
-		t.PermitCycles = true
+		t.PreventCycles = true
 	}
 }
diff --git a/undirected.go b/undirected.go
index d7c3e82..91d2c0a 100644
--- a/undirected.go
+++ b/undirected.go
@@ -82,8 +82,8 @@ func (u *undirected[K, T]) AddEdge(sourceHash, targetHash K, options ...func(*Ed
 		return fmt.Errorf("an edge between vertices %v and %v already exists", sourceHash, targetHash)
 	}
 
-	// If the user opted in to permitting cycles, run a cycle check.
-	if u.traits.PermitCycles {
+	// If the user opted in to preventing cycles, run a cycle check.
+	if u.traits.PreventCycles {
 		createsCycle, err := CreatesCycle[K, T](u, sourceHash, targetHash)
 		if err != nil {
 			return fmt.Errorf("failed to check for cycles: %w", err)


Test patch:
diff --git a/dag_test.go b/dag_test.go
index 9ab34a2..517774f 100644
--- a/dag_test.go
+++ b/dag_test.go
@@ -24,7 +24,7 @@ func TestDirectedTopologicalSort(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := New(IntHash, Directed(), PermitCycles())
+		graph := New(IntHash, Directed(), PreventCycles())
 
 		for _, vertex := range test.vertices {
 			_ = graph.AddVertex(vertex)
@@ -108,7 +108,7 @@ func TestDirectedTransitiveReduction(t *testing.T) {
 	}
 
 	for name, test := range tests {
-		graph := New(StringHash, Directed(), PermitCycles())
+		graph := New(StringHash, Directed(), PreventCycles())
 
 		for _, vertex := range test.vertices {
 			_ = graph.AddVertex(vertex)
diff --git a/directed_test.go b/directed_test.go
index 5168f1f..f6b2cb7 100644
--- a/directed_test.go
+++ b/directed_test.go
@@ -142,7 +142,7 @@ func TestDirected_AddEdge(t *testing.T) {
 				{Source: 3, Target: 1},
 			},
 			traits: &Traits{
-				PermitCycles: true,
+				PreventCycles: true,
 			},
 			shouldFinallyFail: true,
 		},
diff --git a/traits_test.go b/traits_test.go
index c91e6d8..169d259 100644
--- a/traits_test.go
+++ b/traits_test.go
@@ -113,14 +113,14 @@ func TestTree(t *testing.T) {
 	}
 }
 
-func TestPermitCycles(t *testing.T) {
+func TestPreventCycles(t *testing.T) {
 	tests := map[string]struct {
 		expected *Traits
 	}{
-		"permit cycles": {
+		"prevent cycles": {
 			expected: &Traits{
-				IsAcyclic:    true,
-				PermitCycles: true,
+				IsAcyclic:     true,
+				PreventCycles: true,
 			},
 		},
 	}
@@ -128,7 +128,7 @@ func TestPermitCycles(t *testing.T) {
 	for name, test := range tests {
 		p := &Traits{}
 
-		PermitCycles()(p)
+		PreventCycles()(p)
 
 		if !traitsAreEqual(test.expected, p) {
 			t.Errorf("%s: trait expectation doesn't match: expected %v, got %v", name, test.expected, p)
@@ -141,5 +141,5 @@ func traitsAreEqual(a, b *Traits) bool {
 		a.IsDirected == b.IsDirected &&
 		a.IsRooted == b.IsRooted &&
 		a.IsWeighted == b.IsWeighted &&
-		a.PermitCycles == b.PermitCycles
+		a.PreventCycles == b.PreventCycles
 }
diff --git a/undirected_test.go b/undirected_test.go
index c98d942..f56781a 100644
--- a/undirected_test.go
+++ b/undirected_test.go
@@ -133,7 +133,7 @@ func TestUndirected_AddEdge(t *testing.T) {
 			vertices:   []int{1, 2, 3},
 			edgeHashes: [][3]int{{1, 2, 0}, {2, 3, 0}, {3, 1, 0}},
 			traits: &Traits{
-				PermitCycles: true,
+				PreventCycles: true,
 			},
 			shouldFinallyFail: true,
 		},