java.lang.Object
com.darkcollective.relix.semantic.internal.RelationBoundedness
All Implemented Interfaces:
BoundednessSource

public final class RelationBoundedness extends Object implements BoundednessSource
Answers one question about a named relation: is it finite? — the extent of relix.relations.boundedness.

It is a BoundednessSource, which is what makes it one answer rather than two. The lattice, the operator rules and the λ-is-a-rescue exception all live in PropertyDeriver, and this supplies the part that walk cannot know: what a leaf is. A leaf here may be a view, so the two call back and forth — the deriver descends a body, this resolves each name it reaches, and a name that turns out to be another view is derived in turn.

What a name resolves to

  • A view (:=) — derived from its body, so it is exactly as bounded as what it reads. This is the answer worth having: σ n < 100 (Naturals) is still infinite, and λ 10 (Naturals) is not.
  • A generator source — asked of the GeneratorCatalog, the only party that knows. Naturals and Primes are unbounded, Range is not.
  • Any other declared relation — a file, an HTTP resource, a database table, an inline table, a catalog relation — is Boundedness.BOUNDED. Each is a finite extent that some other party is holding.
  • A name that resolves to nothing — Boundedness.UNKNOWN. Unlike the planner's source, which reads an unrecognised leaf as bounded rather than risk refusing a legal query, a catalog has no such stake: it is stating a fact, and the fact about a relation it cannot see is that it does not know one.

A cycle answers UNKNOWN

Mutually recursive definitions (A := σ … (B); B := σ … (A)) terminate on a visiting set, and re-entering a name in progress yields UNKNOWN rather than the lattice's identity. RelationDeterminism makes the opposite choice on the same shape for a good reason that does not hold here: its fold is a conjunction, so the walk still in progress covers whatever the re-entry would have found. A least upper bound has no such reading — returning BOUNDED would let a cycle claim to be finite, which is precisely what nobody can show.

Not thread-safe, and not meant to be: an instance carries the walk it is on, and one is built per analysis.

  • Constructor Details

    • RelationBoundedness

      public RelationBoundedness(SymbolTable symbols, Map<String,SourceDeclaration> sources, GeneratorCatalog generators)
      Parameters:
      symbols - resolves a name to its symbol — dotted references included; must not be null
      sources - source declarations by canonical (lower-cased) name, as in SemanticModel.sources(), which is where a generator source's name and arguments are; must not be null
      generators - the installed generators, asked whether one of them is infinite; must not be null (GeneratorCatalog.NONE answers Boundedness.UNKNOWN for every generator, which is the honest report from a session with no registry wired in)
  • Method Details

    • boundednessOf

      public Boundedness boundednessOf(String relationName)
      Returns the boundedness of the relation named relationName.

      An unresolvable name is Boundedness.UNKNOWN; see of(com.darkcollective.relix.symbol.relation.RelationSymbol) for the rest.

      Specified by:
      boundednessOf in interface BoundednessSource
      Parameters:
      relationName - the relation name, qualified or not; must not be null
      Returns:
      the boundedness of the relation named relationName
    • of

      public Boundedness of(RelationSymbol symbol)
      Returns the boundedness of symbol.

      The entry point for a caller that already holds the symbol, which is every caller building a row about a relation rather than following a reference to one — it skips a name resolution that could land on a same-named relation in another namespace.

      Parameters:
      symbol - the relation; must not be null
      Returns:
      the boundedness of symbol