Recursive constraints: What does DBase<T> : where T : DBase<T> mean?

dbase commands with examples
what is a dbase table
wikipedia dbf
dbf
foxpro dbase
dbf file viewer
dbase download
foxpro file format

I thought I understood generic constraints until I ran across this.

public class DBase<T> : DbContext, IDisposable where T : DBase<T>

How can T be DBase<T>? And if it can, what does it mean? This code compiles and runs fine. I'm not fixing a problem. I just don't understand it.

It is used here

    public class ChildDb : DBase<ChildDb>

Which, again, doesn't compute for me. It passes itself as a type parameter?

How can T be DBase<T>?

There is no limitation that prevents a Generic Parameter from deriving from itself. While it's not directly understandable with the example you've given. What about a Vertex / Vertice?

Excerpt from Wikipedia:

In geometry, a vertex (plural: vertices or vertexes) is a point where two or more curves, lines, or edges meet. As a consequence of this definition, the point where two lines meet to form an angle and the corners of polygons and polyhedra are vertices.1

How does one describe a Vertex (a point)?

// very simplified example
public class Vertex
{
  public int X { get; set; }
  public int Y { get; set; }
}

Now how do we add a collection of relationed Verticies to this class but only allow things that derive from this class?

public class Vertex<TVertex> : Vertex
  where TVertex : Vertex<TVertex>
{
  public IEnumerable<TVertex> Vertices { get; set; }
}

It a generic version of say:

public Vertex2
{
  public IENumerable<Vertex2> Vertices { get; set; }
}

However when I derive from Vertex2, my Vertices will always have to be IEnumerable<Vertex2>, and the correct way to allow Vertices to be a derived class is to use this type of self-reference generic.

I'm sorry Erik, I lost the point in the details. What have I gained by the recursion?

Using Vertex2, our derived types lose access to other derived properties:

public class MyVertex2: Vertex2
{
  public int Id { get; set; }
}

so

var a = new MyVertex2 {Id = 1 };
var b = new MyVertex2 { Id = 2 };
a.Vertices = new List<Vertex2> { b };
b.Vertices = new List<Vertex2> { a };

// can't access Id because it's a Vertex2 not a MyVertex2
var bId = a.Vertices.First().Id;

Sure you could cast it, but then you're casting it everywhere (that's not DRY)... and what if it's not a MyVertex (MullReferencesException or InvalidCastException).

public class MyVertex: Vertex<MyVertex>
{
  public int Id { get; set; }
}
var a = new MyVertex {Id = 1 };
var b = new MyVertex { Id = 2 };
a.Vertices = new List<MyVertex > { b };
b.Vertices = new List<MyVertex > { a };

var bId = a.Vertices.First().Id;
// or even
var aId = a.Vertices.First().Vertices.First();

each time we navigate to a vertices we get the correct derived type, not the base class.

Computer Vision and Graphics: Second International Conference, , where B(Center)i represents the central bone at the ith frame and θ is in the the Similarity between Two Human Motions: Constrained Dynamic Time Warping Dynamic Time Warping cDTW is defined recursively as follows [16]: Dbase(u,  DBase is a microcomputer database management system (DBMS) that runs on a Windows platform. DBase is unique in that it allows for the hassle-free production of a wide variety of applications, including middleware applications, Web apps hosted on Windows servers and Windows rich client applications. DBase is designed to manipulate relational

John Wu posted a great blog in the comments, the TLDR of which is:

This code pattern allows you to declare a superclass that must be extended (possibly not by you, if you're writing a library that other people will use) in order to be used, but can have a bunch of methods/signatures (written by you) that return T when you write them but in practice will return objects of the child type (not written by you/you cannot know) so they can be used in a chained fashion (like the way most StringBuilder methods return the StringBuilder itself so the user can call .Append().AppendLine() ) without needing to be cast (in the code not written by you) from the parent type (written by you) to the child type (not written by you)

There's a caveat: it's not particularly useful because only the deepest child in an inheritance tree can be instantiated. Avoid using it

Modeling Languages in Mathematical Optimization, One could automatically generate databases in dBASE format, the algebraic structure Hierarchical sets were especially appealing since many constraints were as trees: Constraints were generated recursively from the top down the tree. This project ended in 2001 and the result was basically, what LPL is today​: A  dBASE is a well-documented format. Documentation: See DBF for general documentation for the dBase Table format. The Shapefile format, including the constraints on the dBASE Table File for use in a Shapefile, is defined in ESRI Shapefile Technical Description, July 1998. The description of the .dbf file is on page 25. Adoption: See ESRI_shape

As a useful example, it allows you to have some methods or properties in the base class which return derived type.

For example, in the fluent builders which have chainable methods, let's say we have a base builder which set some common properties. What should be the output type of these methods?

See the following example:

public abstract class Control
{
    public string Id { get; set; }
}
public abstract class ControlBuilder<TBuilder, TControl>
    where TBuilder : ControlBuilder<TBuilder, TControl>, new()
    where TControl : Control, new()
{
    protected TControl control;
    protected ControlBuilder()
    {
        control = new TControl();
    }
    public static TBuilder With()
    {
        return new TBuilder();
    }
    public TControl Build()
    {
        control;
    }
    public TBuilder Id(string id)
    {
        control.Id = id;
        return (TBuilder)this;
    }
}

Without having ControlBuilder<TBuilder, TControl> as a constraint for TBuilder, how you can return a TBuilder from Id method?

If you say ask why not return ControlBuilder<TBuilder, TControl>, because if you return it, after calling .Id("something") in method chains, it will not show derived class methods and it just will show methods of ControlBuilder<TBuilder, TControl>.

Let's say we create a TextBoxBuilder for building a TextBox:

public class TextBox : Control
{
    public string Text { get; set; }
}
public class TextBoxBuilder : ControlBuilder<TextBoxBuilder, TextBox>
{
    public TextBoxBuilder Text(string text)
    {
        control.Text = text;
        return this;
    }
}

Now we can use it as expected:

var txt = TextBoxBuilder.With().Id("textBox1").Text("Hello!").Build();

[PDF] Language Reference 110502.book, Chapter 12, “Xbase,” is a reference to legacy dBASE data manipulation and utility commands and functions. Entries include an object-oriented DML equivalent,  dBase (also stylized dBASE) was one of the first database management systems for microcomputers, and the most successful in its day. The dBase system includes the core database engine, a query system, a forms engine, and a programming language that ties all of these components together. dBase's underlying file format, the .dbf file, is widely used in applications needing a simple format to

dBASE .DBF File Structure, 01 for the first field in the table, 02 for the second field, etc. Note: this will be 0 in the case of a constraint. 4, 8-bit number, Which property is described in this record: A quick history lessons for you young 'uns: Back in the 1980s, dBASE was the standard PC database application, until 1988 when Ashton-Tate, the developer, released dBASE IV. If you think Windows 8

dBASE Table File Format (DBF), The constraints on the DBF for PC ArcInfo Coverage are believed to be similar to those for ESRI Shapefiles (Shape_DBF). Local use Explanation  Chapter 9 Integrity Rules and Constraints Adrienne Watt & Nelson Eng. Constraints are a very important feature in a relational model. In fact, the relational model supports the well-defined theory of constraints on attributes or tables. Constraints are useful because they allow a designer to specify the semantics of data in the database.

Recursive CTEs and Foreign Key References in SQL Server, Introduction. Foreign key constraints are a powerful mechanism for preserving referential integrity in a database. They can also represent a  (The following example is for Visual dBASE 7.x, but the concepts are good across the board for later versions of the software -- dB2K does not use the MUGS example, but you will see DQUERY and some other aliases.) When you install Visual dBASE several aliases are created for you, for example "MUGS" and "VDBSAMPLE".

Comments
  • This way you can set all the generic methods to require T to be of the same type as the declaring type. See blogs.msdn.microsoft.com/simonince/2008/06/12/…
  • This is known as the curiously repeating template pattern or CRTP.
  • Fascinating. Do you want to post either of these as an answer so I can acknowledge it?
  • It's usually useful for creating fluent builders having chainable methods. In this example you see, this pattern is useful to let the base class, have a method which returns the derived class instance.
  • Any of the three of these seem to be valid answers. I'll wait a week and see which is upvoted.
  • Good example but requires knowledge of Mathematics :)
  • I'm sorry Erik, I lost the point in the details. What have I gained by the recursion? Wouldn't this be better: "<T> where T: Vertex" where Vertex is the original class rather than the generic. I'm clearly still missing something.
  • @BWhite if it's not the generic class you can't navigate to any other Vertex, because you don't have the Vertices class.
  • I get it. Thanks for the clarification. To sum up, it's all about the class being able to use the correct descendant type. I was just looking at the code instead of how it was called.
  • I know the example seems a bit complex, but if you try it in action and try to answer Without having ControlBuilder<TBuilder, TControl> as a constraint for TBuilder, how you can return a TBuilder from Id method you will see if you don't have that constraint, then after calling TextBoxBuilder.With().Id("textBox1") methods of TextBoxBuilder will not appear and you just see methods of base ControlBuilder. I suggest you to try it in action to get it better. Hope it helps :)